STL相關的面試題
了解STL嗎?
0:STL常用的容器有哪些以及各自的特點是什么?
1.vector:底層數據結構為數組 ,支持快速隨機訪問。 2.list:底層數據結構為雙向鏈表,支持快速增刪。 3.deque:底層數據結構為一個中央控制器和多個緩沖區,支持首尾(中間不能)快速增刪,也支持隨機訪問。 4.stack:底層一般用23實現,封閉頭部即可,不用vector的原因應該是容量大小有限制,擴容耗時 5.queue:底層一般用23實現,封閉頭部即可,不用vector的原因應該是容量大小有限制,擴容耗時(stack和queue其實是適配器,而不叫容器,因為是對容器的再封裝) 6.priority_queue:的底層數據結構一般為vector為底層容器,堆heap為處理規則來管理底層容器實現 7.set:底層數據結構為紅黑樹,有序,不重復。 8.multiset:底層數據結構為紅黑樹,有序,可重復。 9.map:底層數據結構為紅黑樹,有序,不重復。 10.multimap:底層數據結構為紅黑樹,有序,可重復。 11.hash_set:底層數據結構為hash表,無序,不重復。 12.hash_multiset:底層數據結構為hash表,無序,可重復 。 13.hash_map :底層數據結構為hash表,無序,不重復。 14.hash_multimap:底層數據結構為hash表,無序,可重復。
使用場景
1、如果你需要高效的隨機存取,而不在乎插入和刪除的效率,使用vector
2、如果你需要大量的插入和刪除,而不關心隨機存取,則應使用list
3、如果你需要隨機存取,而且關心兩端數據的插入和刪除,則應使用deque。
4、如果你要存儲一個數據字典,並要求方便地根據key找value,那么map是較好的選擇
5、如果你要查找一個元素是否在某集合內存中,則使用set存儲這個集合比較好
1:說說 vector 和 list 的區別
1) vector, 連續存儲的容器,動態數組,在堆上分配空間 ;
底層實現:數組。
如果沒有剩余空間了,則會重新配置原有元素個數的兩倍空間,然后將原空間元素通過復制的方式初始化新空間,再向新空間增加元素。
適用場景:經常隨機訪問,且不經常對非尾節點進行插入刪除。
2)list,動態鏈表,在堆上分配空間,每插入一個元素都會分配空間,每刪除一個元素都會釋放空間。
底層:雙向鏈表
訪問:隨機訪問性能很差,只能快速訪問頭尾節點。
適用場景:經常插入刪除大量數據
2) vector在中間節點進行插入刪除會導致內存拷貝,list不會。
3) vector一次性分配好內存,不夠時才進行2倍擴容;list每次插入新節點都會進行內存申請。
4) vector擁有一段連續的內存空間,因此支持隨機訪問,如果需要高效的隨即訪問,而不在乎插入和刪除的效率,使用vector。
list擁有一段不連續的內存空間,如果需要高效的插入和刪除,而不關心隨機訪問,則應使用list。
2 map 和 set 有什么區別
1) map和set都是C++的關聯容器,其底層實現都是紅黑樹(RB-Tree)。
2) map中的元素是key-value(關鍵字—值)對:關鍵字起到索引的作用,值則表示與索引相關聯的數據;Set與之相對就是關鍵字的簡單集合,set中每個元素只包含一個關鍵字。
3) set的迭代器是const的,不允許修改元素的值;map允許修改value,但不允許修改key。
4) map支持下標操作,set不支持下標操作。map可以用key做下標,
2.1unordered_map和map 說說區別
內部實現機理
- map: map內部實現了一個紅黑樹,該結構具有自動排序的功能,因此map內部的所有元素都是有序的,紅黑樹的每一個節點都代表着map的一個元素,因此,對於map進行的查找,刪除,添加等一系列的操作都相當於是對紅黑樹進行這樣的操作,故紅黑樹的效率決定了map的效率。
- unordered_map: unordered_map內部實現了一個哈希表,因此其元素的排列順序是雜亂的,無序的
優缺點以及適用處
- map
- 優點:
- 有序性,這是map結構最大的優點,其元素的有序性在很多應用中都會簡化很多的操作
- 紅黑樹,內部實現一個紅黑書使得map的很多操作在的時間復雜度下就可以實現,因此效率非常的高
- 缺點:
適用處,對於那些有順序要求的問題,用map會更高效一些- 空間占用率高,因為map內部實現了紅黑樹,雖然提高了運行效率,但是因為每一個節點都需要額外保存父節點,孩子節點以及紅/黑性質,使得每一個節點都占用大量的空間
- 優點:
- unordered_map
- 優點:
- 因為內部實現了哈希表,因此其查找速度非常的快
- 缺點:
適用處,對於查找問題,unordered_map會更加高效一些,因此遇到查找問題,常會考慮一下用unordered_map- 哈希表的建立比較耗費時間
- 優點:
3 STL 中迭代器的作用,有指針為何還要迭代器
1) Iterator(迭代器)模式又稱Cursor(游標)模式,用於提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。
2) 迭代器不是指針,是類模板,表現的像指針。他只是模擬了指針的一些功能,通過重載了指針的一些操作符,->、*、++、--等,相當於一種智能指針。
3) 迭代器產生原因:
Iterator類的訪問方式就是把不同集合類的訪問邏輯抽象出來,使得不用暴露集合內部的結構而達到循環遍歷集合的效果。
4 STL 迭代器是怎么刪除元素的呢
1) 對於序列容器vector,deque來說,使用erase(itertor)后,后邊的每個元素的迭代器都會失效,但是后邊每個元素都會往前移動一個位置,但是erase會返回下一個有效的迭代器;
2) 對於關聯容器map set來說,使用了erase(iterator)后,當前元素的迭代器失效,但是其結構是紅黑樹,刪除當前元素的,不會影響到下一個元素的迭代器,所以在調用erase之前,記錄下一個元素的迭代器即可。
3) 對於list來說,它使用了不連續分配的內存,並且它的erase方法也會返回下一個有效的iterator,
5平衡二叉樹(AVL樹)和紅黑樹
1)平衡二叉樹又稱為AVL樹,是一種特殊的二叉排序樹。其左右子樹都是平衡二叉樹,且左右子樹高度之差的絕對值不超過1。
2)紅黑樹是一種二叉查找樹,但在每個節點增加一個存儲位表示節點的顏色,可以是紅或黑(非紅即黑),紅黑樹是一種弱平衡二叉樹,相對於要求嚴格的AVL樹來說,它的旋轉次數少,所以對於搜索,插入,刪除操作較多的情況下,通常使用紅黑樹。
3)所以紅黑樹在查找,插入刪除的性能都是O(logn),且性能穩定,所以STL里面很多結構包括map底層實現都是使用的紅黑樹。

請你回答一下map底層為什么用紅黑樹實現 1、紅黑樹: 紅黑樹是一種二叉查找樹,但在每個節點增加一個存儲位表示節點的顏色,可以是紅或黑(非紅即黑)。通過對任何一條從根到葉子的路徑上各個節點着色的方式的限制,紅黑樹確保沒有一條路徑會比其它路徑長出兩倍,因此,紅黑樹是一種弱平衡二叉樹,相對於要求嚴格的AVL樹來說,它的旋轉次數少,所以對於搜索,插入,刪除操作較多的情況下,通常使用紅黑樹。 性質: 1. 每個節點非紅即黑 2. 根節點是黑的; 3. 每個葉節點(葉節點即樹尾端NULL指針或NULL節點)都是黑的; 4. 如果一個節點是紅色的,則它的子節點必須是黑色的。 5. 對於任意節點而言,其到葉子點樹NULL指針的每條路徑都包含相同數目的黑節點; 2、平衡二叉樹(AVL樹): 紅黑樹是在AVL樹的基礎上提出來的。 平衡二叉樹又稱為AVL樹,是一種特殊的二叉排序樹。其左右子樹都是平衡二叉樹,且左右子樹高度之差的絕對值不超過1。 AVL樹中所有結點為根的樹的左右子樹高度之差的絕對值不超過1。 將二叉樹上結點的左子樹深度減去右子樹深度的值稱為平衡因子BF,那么平衡二叉樹上的所有結點的平衡因子只可能是-1、0和1。只要二叉樹上有一個結點的平衡因子的絕對值大於1,則該二叉樹就是不平衡的。 3、紅黑樹較AVL樹的優點: AVL 樹是高度平衡的,頻繁的插入和刪除,會引起頻繁的rebalance,導致效率下降;紅黑樹不是高度平衡的,算是一種折中,插入最多兩次旋轉,刪除最多三次旋轉。 所以紅黑樹在查找,插入刪除的性能都是O(logn),且性能穩定,所以STL里面很多結構包括map底層實現都是使用的紅黑樹。
6 棧溢出的原因
棧溢出指的是程序向棧中某個變量中寫入的字節數超過了這個變量本身所申請的字節數。
1) 局部數組過大。當函數內部的數組過大時,有可能導致堆棧溢出,局部變量是存儲在棧中的。
2) 遞歸調用層次太多。
3) 指針或數組越界。例如進行字符串拷貝,或處理用戶輸入等等。
7 堆和棧的區別
C語言的內存模型分為5個區:棧區、堆區、靜態區、常量區、代碼區。
1) 棧區:存放函數的參數值、局部變量等,由編譯器自動分配和釋放。棧由系統自動分配,速度快,但是程序員無法控制。
2) 堆區:就是通過new、malloc、realloc分配的內存塊,編譯器不會負責它們的釋放工作。一般是由程序員分配釋放,未被釋放可能引起內存泄漏。堆是有程序員自己分配,速度較慢,容易產生碎片,不過用起來方便。
3) 全局變量和靜態變量的存儲是放在一塊的。
4) 常量區:常量存儲在這里,不允許修改。
5) 代碼區:存放函數體的二進制代碼。
8 哈希表(hash表)
哈希表的實現主要包括構造哈希和處理哈希沖突:構造哈希,主要包括直接地址法,除留余數法。
處理哈希沖突:當哈希表關鍵字集合很大時,關鍵字值不同的元素可能會映射到哈希表的同一地址上,這樣的現象稱為哈希沖突。常用的解決方法有:
1) 開放定址法,沖突時,用某種方法繼續探測哈希表中的其他存儲單元,直到找到空位置為止。(如,線性探測,平方探測)
2) 再哈希法:當發生沖突時,用另一個哈希函數計算地址值,直到沖突不再發生。
3) 鏈地址法:將所有哈希值相同的key通過鏈表存儲,key按順序插入鏈表中。