二十万字C/C++、嵌入式软开面试题全集宝典四
目錄
1、 虛函數的代價?
2、 用C語言實現C++的繼承
3、 繼承機制中對象之間如何轉換?指針和引用之間如何轉換?
4、 C++四種類型轉換
5、 為什么要用static_cast轉換而不用c語言中的轉換?
6、 組合與繼承優缺點?
7、 左值右值
8、 總結左值和右值的概念
9、 移動構造函數
10、 C語言的編譯鏈接過程?
11、 vector與list的區別與應用?怎么找某vector或者list的倒數第二個元素
12、 STL vector的實現,刪除其中的元素,迭代器如何變化?為什么是兩倍擴容?釋放空間?
13、 容器內部刪除一個元素
14、 STL迭代器如何實現
15、 set與hash_set的區別
16、 hash_map與map的區別
17、 map、set是怎么實現的,紅黑樹是怎么能夠同時實現這兩種容器?為什么使用紅黑樹?
18、 如何在共享內存上使用stl標準庫?
19、 map插入方式有幾種?
20、 STL中unordered_map(hash_map)和map的區別,hash_map如何解決沖突以及擴容
?
?
1、 虛函數的代價?
1.帶有虛函數的類,每一個類會產生一個虛函數表,用來存儲指向虛成員函數的指針,增大類;
2.帶有虛函數的類的每一個對象,都會有一個指向虛表的指針,會增加對象的空間大小;
3.不能再是內聯的函數,因為內聯函數在編譯階段進行替代,而虛函數表示等待,在運行階段才能確定到底是采用哪種函數,虛函數不能是內聯函數。
2、 用C語言實現C++的繼承
#include <iostream>using namespace std;//C++中的繼承與多態struct A{virtual void fun()????//C++中的多態:通過虛函數實現{cout<<"A:fun()"<<endl;}int a;};struct B:public A?????????//C++中的繼承:B類公有繼承A類{virtual void fun()????//C++中的多態:通過虛函數實現(子類的關鍵字virtual可加可不加){cout<<"B:fun()"<<endl;}int b;};//C語言模擬C++的繼承與多態typedef void (*FUN)();??????//定義一個函數指針來實現對成員函數的繼承struct _A???????//父類{FUN _fun;???//由于C語言中結構體不能包含函數,故只能用函數指針在外面實現int _a;};struct _B?????????//子類{_A _a_;?????//在子類中定義一個基類的對象即可實現對父類的繼承int _b;};void _fA()???????//父類的同名函數{printf("_A:_fun()\n");}void _fB()???????//子類的同名函數{printf("_B:_fun()\n");}void Test(){//測試C++中的繼承與多態A a;????//定義一個父類對象aB b;????//定義一個子類對象bA* p1 = &a;???//定義一個父類指針指向父類的對象p1->fun();????//調用父類的同名函數p1 = &b;??????//讓父類指針指向子類的對象p1->fun();????//調用子類的同名函數//C語言模擬繼承與多態的測試_A _a;????//定義一個父類對象_a_B _b;????//定義一個子類對象_b_a._fun = _fA;????????//父類的對象調用父類的同名函數_b._a_._fun = _fB;????//子類的對象調用子類的同名函數_A* p2 = &_a;???//定義一個父類指針指向父類的對象p2->_fun();?????//調用父類的同名函數p2 = (_A*)&_b;??//讓父類指針指向子類的對象,由于類型不匹配所以要進行強轉p2->_fun();?????//調用子類的同名函數}3、 繼承機制中對象之間如何轉換?指針和引用之間如何轉換?
1.向上類型轉換
將派生類指針或引用轉換為基類的指針或引用被稱為向上類型轉換,向上類型轉換會自動進行,而且向上類型轉換是安全的。
2.向下類型轉換
將基類指針或引用轉換為派生類指針或引用被稱為向下類型轉換,向下類型轉換不會自動進行,因為一個基類對應幾個派生類,所以向下類型轉換時不知道對應哪個派生類,所以在向下類型轉換時必須加動態類型識別技術。RTTI技術,用dynamic_cast進行向下類型轉換。
4、 C++四種類型轉換
C++的四種強制轉換包括:static_cast,?dynamic_cast, const_cast, reinterpret_cast。
1.static_cast能進行基礎類型之間的轉換,也是最常看到的類型轉換。明確指出類型轉換,?般建議將隱式轉換都替換成顯示轉換,因為沒有動態類型檢查,上?轉換(派?類->基類)安全,下?轉換(基類->派?類) 不安全,所以主要執??多態的轉換操作;
它主要有如下幾種用法:
1用于類層次結構中父類和子類之間指針或引用的轉換。進行上行轉換(把子類的指針或引用轉換成父類表示)是安全的;
2進行下行轉換(把父類指針或引用轉換成子類指針或引用)時,由于沒有動態類型檢查,所以是不安全的;
3用于基本數據類型之間的轉換,如把int轉換成char,把int轉換成enum。這種轉換的安全性也要開發人員來保證。
4把void指針轉換成目標類型的指針(不安全!!)
5把任何類型的表達式轉換成void類型。
2.const_cast專??于const,volatile屬性的轉換,去除const性質,或增加const性質,是四個轉換符中唯??個可以操作常量的轉換符。除了去掉const 或volatile修飾之外,type_id和expression得到的類型是一樣的。但需要特別注意的是const_cast不是用于去除變量的常量性,而是去除指向常數對象的指針或引用的常量性,其去除常量性的對象必須為指針或引用。
3.reinterpret_cast不到萬不得已,不要使?這個轉換符,?危操作。使?特點:從底層對數據進?重新解釋,依賴具體的平臺,可移植性差。它可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針(先把一個指針轉換成一個整數,在把該整數轉換成原類型的指針,還可以得到原先的指針值)。可以在指針和引?之間進?肆?忌憚的轉換。
4.dynamic_cast 專??于派?類之間的轉換,type-id必須是類指針,類引?或void*,主要用在繼承體系中的安全向下轉型。它能安全地將指向基類的指針轉型為指向子類的指針或引用,并獲知轉型動作成功是否。當類型不?致時,轉型失敗會返回null(轉型對象為指針時)或拋出異常bad_cast(轉型對象為引用時),?static_cast,當類型不?致時,轉換過來的事錯誤意義的指針,可能造成?法訪問等問題。dynamic_cast 會動用運行時信息(RTTI)來進行類型安全檢查,因此?dynamic_cast?存在一定的效率損失。當使用dynamic_cast時,該類型必須含有虛函數,這是因為dynamic_cast使用了存儲在VTABLE中的信息來判斷實際的類型,RTTI運行時類型識別用于判斷類型。typeid表達式的形式是typeid(e),typeid操作的結果是一個常量對象的引用,該對象的類型是type_info或type_info的派生。
5、 為什么要用static_cast轉換而不用c語言中的轉換?
1.更加安全;
2.更直接明顯,能夠一眼看出是什么類型轉換為什么類型,容易找出程序中的錯誤;可清楚地辨別代碼中每個顯式的強制轉;可讀性更好,能體現程序員的意圖
6、 組合與繼承優缺點?
一、繼承
繼承是is a 的關系,比如說Student繼承Person,則說明Student is a Person。繼承的優點是子類可以重寫父類的方法來方便地實現對父類的擴展。
繼承的缺點有以下幾點:
①:父類的內部細節對子類是可見的。
②:子類從父類繼承的方法在編譯時就確定下來了,所以無法在運行期間改變從父類繼承的方法的行為。
③:如果對父類的方法做了修改的話(比如增加了一個參數),則子類的方法必須做出相應的修改。所以說子類與父類是一種高耦合,違背了面向對象思想。
二、組合
組合也就是設計類的時候把要組合的類的對象加入到該類中作為自己的成員變量。
組合的優點:
①當前對象只能通過所包含的那個對象去調用其方法,所以所包含的對象的內部細節對當前對象時不可見的。
②當前對象與包含的對象是一個低耦合關系,如果修改包含對象的類中代碼不需要修改當前對象類的代碼。
③當前對象可以在運行時動態的綁定所包含的對象。可以通過set方法給所包含對象賦值。
組合的缺點:
①容易產生過多的對象。
②為了能組合多個對象,必須仔細對接口進行定義。
7、 左值右值
1.在C++11中所有的值必屬于左值、右值兩者之一,右值又可以細分為純右值、將亡值。在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、沒有名字的就是右值(將亡值或純右值)。舉個例子,int a = b+c, a 就是左值,其有變量名為a,通過&a可以獲取該變量的地址;表達式b+c、函數int func()的返回值是右值,在其被賦值給某一變量前,我們不能通過變量名找到它,&(b+c)這樣的操作則不會通過編譯。
2.C++11對C++98中的右值進行了擴充。在C++11中右值又分為純右值(prvalue,Pure Rvalue)和將亡值(xvalue,eXpiring Value)。其中純右值的概念等同于我們在C++98標準中右值的概念,指的是臨時變量和不跟對象關聯的字面量值;將亡值則是C++11新增的跟右值引用相關的表達式,這樣表達式通常是將要被移動的對象(移為他用),比如返回右值引用T&&的函數返回值、std::move的返回值,或者轉換為T&&的類型轉換函數的返回值。將亡值可以理解為通過“盜取”其他變量內存空間的方式獲取到的值。在確保其他變量不再被使用、或即將被銷毀時,通過“盜取”的方式可以避免內存空間的釋放和分配,能夠延長變量值的生命期。
3.左值引用就是對一個左值進行引用的類型。右值引用就是對一個右值進行引用的類型,事實上,由于右值通常不具有名字,我們也只能通過引用的方式找到它的存在。右值引用和左值引用都是屬于引用類型。無論是聲明一個左值引用還是右值引用,都必須立即進行初始化。而其原因可以理解為是引用類型本身自己并不擁有所綁定對象的內存,只是該對象的一個別名。左值引用是具名變量值的別名,而右值引用則是不具名(匿名)變量的別名。左值引用通常也不能綁定到右值,但常量左值引用是個“萬能”的引用類型。它可以接受非常量左值、常量左值、右值對其進行初始化。不過常量左值所引用的右值在它的“余生”中只能是只讀的。相對地,非常量左值只能接受非常量左值對其進行初始化。
4.右值引用通常不能綁定到任何的左值,要想綁定一個左值到右值引用,通常需要std::move()將左值強制轉換為右值。
lsy注:推薦去看一下move源碼,很巧妙的用法!
8、 總結左值和右值的概念
1.左值是可以放在賦值號左邊可以被賦值的值;左值必須要在內存中有實體;
2.右值當在賦值號右邊取出值賦給其他變量的值;右值可以在內存也可以在CPU寄存器。
3.一個對象被用作右值時,使用的是它的內容(值),被當作左值時,使用的是它的地址。
4.左值:指表達式結束后依然存在的持久對象,可以取地址,具名變量或對象?。
5.右值:表達式結束后就不再存在的臨時對象,不可以取地址,沒有名字。
9、 移動構造函數
1.我們用對象a初始化對象b后,對象a我們就不在使用了,但是對象a的空間還在呀(在析構之前),既然拷貝構造函數,實際上就是把a對象的內容復制一份到b中,那么為什么我們不能直接使用a的空間呢?這樣就避免了新的空間的分配,大大降低了構造的成本。這就是移動構造函數設計的初衷;
2.拷貝構造函數中,對于指針,我們一定要采用深層復制,而移動構造函數中,對于指針,我們采用淺層復制。淺層復制之所以危險,是因為兩個指針共同指向一片內存空間,若第一個指針將其釋放,另一個指針的指向就不合法了。所以我們只要避免第一個指針釋放空間就可以了。避免的方法就是將第一個指針(比如a->value)置為NULL,這樣在調用析構函數的時候,由于有判斷是否為NULL的語句,所以析構a的時候并不會回收a->value指向的空間;
3.C++引入了移動構造函數,專門處理這種,用a初始化b后,就將a析構的情況;
4.移動構造函數的參數和拷貝構造函數不同,拷貝構造函數的參數是一個左值引用,但是移動構造函數的初值是一個右值引用。意味著,移動構造函數的參數是一個右值或者將亡值的引用。也就是說,只用用一個右值,或者將亡值初始化另一個對象的時候,才會調用移動構造函數。而那個move語句,就是將一個左值變成一個將亡值。
5.與拷貝類似,移動也使用一個對象的值設置另一個對象的值。但是,又與拷貝不同的是,移動實現的是對象值真實的轉移(源對象到目的對象):源對象將丟失其內容,其內容將被目的對象占有。移動操作的發生的時候,是當移動值的對象是未命名的對象的時候。這里未命名的對象就是那些臨時變量,甚至都不會有名稱。典型的未命名對象就是函數的返回值或者類型轉換的對象。使用臨時對象的值初始化另一個對象值,不會要求對對象的復制:因為臨時對象不會有其它使用,因而,它的值可以被移動到目的對象。做到這些,就要使用移動構造函數和移動賦值:當使用一個臨時變量對象進行構造初始化的時候,調用移動構造函數。類似的,使用未命名的變量的值賦給一個對象時,調用移動賦值操作;
Example6 (Example6&& x) : ptr(x.ptr){x.ptr =?nullptr;}// move assignmentExample6&?operator= (Example6&& x){delete ptr;ptr = x.ptr;x.ptr=nullptr;return *this;}10、 C語言的編譯鏈接過程?
源代碼(.c)-->預處理(.i)-->編譯(.s)-->優化-->匯編(.o)-->鏈接-->可執行文件
1、預處理
讀取c源程序,對其中的偽指令(以#開頭的指令)和特殊符號進行處理。包括宏定義替換、條件編譯指令、頭文件包含指令、特殊符號。預編譯程序所完成的基本上是對源程序的“替代”工作。經過此種替代,生成一個沒有宏定義、沒有條件編譯指令、沒有特殊符號的輸出文件。c文件預處理后生成.i,C++文件預處理后生成.ii。
2、編譯階段
編譯程序所要作得工作就是通過詞法分析和語法分析,在確認所有的指令都符合語法規則之后,將其翻譯成等價的中間代碼表示或匯編代碼。生成.s文件
3、匯編過程
匯編過程實際上指把匯編語言代碼翻譯成目標機器指令的過程。對于被翻譯系統處理的每一個C語言源程序,都將最終經過這一處理而得到相應的目標文件。目標文件中所存放的也就是與源程序等效的目標的機器語言代碼。生成.o目標文件
4、鏈接階段
鏈接程序的主要工作就是將有關的目標文件彼此相連接,也即將在一個文件中引用的符號同該符號在另外一個文件中的定義連接起來,使得所有的這些目標文件成為一個能夠被操作系統裝入執行的統一整體。
11、 vector與list的區別與應用?怎么找某vector或者list的倒數第二個元素
1.vector數據結構
vector和數組類似,擁有一段連續的內存空間,并且起始地址不變。因此能高效的進行隨機存取,時間復雜度為o(1);但因為內存空間是連續的,所以在進行插入和刪除操作時,會造成內存塊的拷貝,時間復雜度為o(n)。另外,當數組中內存空間不夠時,會重新申請一塊內存空間并進行內存拷貝。連續存儲結構:vector是可以實現動態增長的對象數組,支持對數組高效率的訪問和在數組尾端的刪除和插入操作,在中間和頭部刪除和插入相對不易,需要挪動大量的數據。它與數組最大的區別就是vector不需程序員自己去考慮容量問題,庫里面本身已經實現了容量的動態增長,而數組需要程序員手動寫入擴容函數進形擴容。
2.list數據結構
list是由雙向鏈表實現的,因此內存空間是不連續的。只能通過指針訪問數據,所以list的隨機存取非常沒有效率,時間復雜度為o(n);但由于鏈表的特點,能高效地進行插入和刪除。非連續存儲結構:list是一個雙鏈表結構,支持對鏈表的雙向遍歷。每個節點包括三個信息:元素本身,指向前一個元素的節點(prev)和指向下一個元素的節點(next)。因此list可以高效率的對數據元素任意位置進行訪問和插入刪除等操作。由于涉及對額外指針的維護,所以開銷比較大。
3、vector與list區別:
1vector的隨機訪問效率高,但在插入和刪除時(不包括尾部)需要挪動數據,不易操作。
2list的訪問要遍歷整個鏈表,它的隨機訪問效率低。但對數據的插入和刪除操作等都比較方便,改變指針的指向即可。list是單向的,vector是雙向的。vector中的迭代器在使用后就失效了,而list的迭代器在使用之后還可以繼續使用。
為什么鏈表插入復雜度不是O(n)而是O(1),不需要找到嗎?
查找并不屬于插入和刪除操作范圍內,你說的情況只能說查找元素的復雜度是O(n)。查找完元素之后才開始插入或刪除,而由于鏈表本身的特性:插入時不用移動后續所有節點或者將整個鏈表拷貝到新的內存空間刪除時可以用下一個節點覆蓋當前節點,將問題轉化成刪除下一個節點所以插入和刪除都是O(1)。
int?mySize = vec.size(); vec.at(mySize -2);list不提供隨機訪問,所以不能用下標直接訪問到某個位置的元素,要訪問list里的元素只能遍歷,不過你要是只需要訪問list的最后N個元素的話,可以用反向迭代器來遍歷:
12、 STL vector的實現,刪除其中的元素,迭代器如何變化?為什么是兩倍擴容?釋放空間?
1、size()函數返回的是已用空間大小,capacity()返回的是總空間大小,capacity()-size()則是剩余的可用空間大小。當size()和capacity()相等,說明vector目前的空間已被用完,如果再添加新元素,則會引起vector空間的動態增長。
2、由于動態增長會引起重新分配內存空間、拷貝原空間、釋放原空間,這些過程會降低程序效率。因此,可以使用reserve(n)預先分配一塊較大的指定大小的內存空間,這樣當指定大小的內存空間未使用完時,是不會重新分配內存空間的,這樣便提升了效率。只有當n>capacity()時,調用reserve(n)才會改變vector容量。resize()成員函數只改變元素的數目,不改變vector的容量。
3、resize()與reserve()
resize()設置大小(size)并初始化新元素;reserve(),設置容量(capacity),只是預留空間,而不會構造新的元素出來
1)空的vector對象,size()和capacity()都為0
2)當空間大小不足時,新分配的空間大小為原空間大小的2倍。
3)使用reserve()預先分配一塊內存后,在空間未滿的情況下,不會引起重新分配,從而提升了效率。
4)當reserve()分配的空間比原空間小時,是不會引起重新分配的。
5)resize()函數只改變容器的元素數目,未改變容器大小。
6)用reserve(size_type)只是擴大capacity值,這些內存空間可能還是“野”的,如果此時使用“[ ]”來訪問,則可能會越界。而resize(size_type new_size)會真正使容器具有new_size個對象。
4、vector擴容方式
1)不同的編譯器,vector有不同的擴容大小。在vs下是1.5倍,在GCC下是2倍;
2)空間和時間的權衡。簡單來說,空間分配的多,平攤時間復雜度低,但浪費空間也多。
3)使用k=2增長因子的問題在于,每次擴展的新尺寸必然剛好大于之前分配的總和,也就是說,之前分配的內存空間不可能被使用。這樣對內存不友好。最好把增長因子設為(1,2)
4)對比可以發現采用采用成倍方式擴容,可以保證常數的時間復雜度,而增加指定大小的容量只能達到O(n)的時間復雜度,因此,使用成倍的方式擴容。
5、如何釋放空間:
由于vector的內存占用空間只增不減,比如你首先分配了10,000個字節,然后erase掉后面9,999個,留下一個有效元素,但是內存占用仍為10,000個。所有內存空間是在vector析構時候才能被系統回收。empty()用來檢測容器是否為空的,clear()可以清空所有元素。但是即使clear(),vector所占用的內存空間依然如故,無法保證內存的回收。
如果需要空間動態縮小,可以考慮使用deque。如果vector,可以用swap()來幫助你釋放內存。
vector(Vec).swap(Vec);//將Vec的內存空洞清除; vector().swap(Vec);//清空Vec的內存;13、 容器內部刪除一個元素
1、順序容器
erase迭代器不僅使所指向被刪除的迭代器失效,而且使被刪元素之后的所有迭代器失效(list除外),所以不能使用erase(it++)的方式,但是erase的返回值是下一個有效迭代器;
It = c.erase(it);
2、關聯容器
erase迭代器只是被刪除元素的迭代器失效,但是返回值是void,所以要采用erase(it++)的方式刪除迭代器;
c.erase(it++)
14、 STL迭代器如何實現
1.迭代器是一種抽象的設計理念,通過迭代器可以在不了解容器內部原理的情況下遍歷容器,除此之外,STL中迭代器一個最重要的作用就是作為容器與STL算法的粘合劑。
2.迭代器的作用就是提供一個遍歷容器內部所有元素的接口,因此迭代器內部必須保存一個與容器相關聯的指針,然后重載各種運算操作來遍歷,其中最重要的是*運算符與->運算符,以及++、--等可能需要重載的運算符重載。這和C++中的智能指針很像,智能指針也是將一個指針封裝,然后通過引用計數或是其他方法完成自動釋放內存的功能。
3.最常用的迭代器的相應型別有五種:value type、difference type、pointer、reference、iterator catagoly;
15、 set與hash_set的區別
1.set底層是以RB-Tree實現,hash_set底層是以hash_table實現的;
2.RB-Tree有自動排序功能,而hash_table不具有自動排序功能;
3.set和hash_set元素的鍵值就是實值;
4.hash_table有一些無法處理的型別;
16、 hash_map與map的區別
1.底層實現不同, hash_map采用hash表存儲,map一般采用紅黑樹(RB Tree)實現;
2.map具有自動排序的功能,hash_map不具有自動排序的功能;
3.hash_table有一些無法處理的型別;
17、 map、set是怎么實現的,紅黑樹是怎么能夠同時實現這兩種容器?為什么使用紅黑樹?
1.他們的底層都是以紅黑樹的結構實現,因此插入刪除等操作都在O(logn)時間內完成,因此可以完成高效的插入刪除;
2.在這里我們定義了一個模版參數,如果它是key那么它就是set,如果它是map,那么它就是map;底層是紅黑樹,實現map的紅黑樹的節點數據類型是key+value,而實現set的節點數據類型是value
3.因為map和set要求是自動排序的,紅黑樹能夠實現這一功能,而且時間復雜度比較低。
18、 如何在共享內存上使用stl標準庫?
1.想像一下把STL容器,例如map, vector, list等等,放入共享內存中,IPC一旦有了這些強大的通用數據結構做輔助,無疑進程間通信的能力一下子強大了很多。我們沒必要再為共享內存設計其他額外的數據結構,另外,STL的高度可擴展性將為IPC所驅使。STL容器被良好的封裝,默認情況下有它們自己的內存管理方案。當一個元素被插入到一個STL列表(list)中時,列表容器自動為其分配內存,保存數據。考慮到要將STL容器放到共享內存中,而容器卻自己在堆上分配內存。一個最笨拙的辦法是在堆上構造STL容器,然后把容器復制到共享內存,并且確保所有容器的內部分配的內存指向共享內存中的相應區域,這基本是個不可能完成的任務。
2.假設進程A在共享內存中放入了數個容器,進程B如何找到這些容器呢?一個方法就是進程A把容器放在共享內存中的確定地址上(fixed offsets),則進程B可以從該已知地址上獲取容器。另外一個改進點的辦法是,進程A先在共享內存某塊確定地址上放置一個map容器,然后進程A再創建其他容器,然后給其取個名字和地址一并保存到這個map容器里。進程B知道如何獲取該保存了地址映射的map容器,然后同樣再根據名字取得其他容器的地址。
19、 map插入方式有幾種?
1.用insert函數插入pair數據,
mapStudent.insert(pair<int, string>(1,?"student_one"));
2.用insert函數插入value_type數據
mapStudent.insert(map<int,string>::value_type(1,?"student_one"));
3.在insert函數中使用make_pair()函數
mapStudent.insert(make_pair(1,?"student_one"));
4.用數組方式插入數據
mapStudent[1] =?"student_one";
20、 STL中unordered_map(hash_map)和map的區別,hash_map如何解決沖突以及擴容
1.unordered_map和map類似,都是存儲的key-value的值,可以通過key快速索引到value。不同的是unordered_map不會根據key的大小進行排序,
2.存儲時是根據key的hash值判斷元素是否相同,即unordered_map內部元素是無序的,而map中的元素是按照二叉搜索樹存儲,進行中序遍歷會得到有序遍歷。
3.所以使用時map的key需要定義operator<。而unordered_map需要定義hash_value函數并且重載operator==。但是很多系統內置的數據類型都自帶這些,
4.那么如果是自定義類型,那么就需要自己重載operator<或者hash_value()了。
5.如果需要內部元素自動排序,使用map,不需要排序使用unordered_map
6.unordered_map的底層實現是hash_table;
7.hash_map底層使用的是hash_table,而hash_table使用的開鏈法進行沖突避免,所有hash_map采用開鏈法進行沖突解決。
8.什么時候擴容:當向容器添加元素的時候,會判斷當前容器的元素個數,如果大于等于閾值---即當前數組的長度乘以加載因子的值的時候,就要自動擴容啦。
9.擴容(resize)就是重新計算容量,向HashMap對象里不停的添加元素,而HashMap對象內部的數組無法裝載更多的元素時,對象就需要擴大數組的長度,以便能裝入更多的元素。
總結
以上是生活随笔為你收集整理的二十万字C/C++、嵌入式软开面试题全集宝典四的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 二十万字C/C++、嵌入式软开面试题全集
- 下一篇: ftpclient读取服务器文件能获得文