c++ stl 之所以得到廣泛的讚譽,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是stl封裝了許多複雜的資料結構演算法和大量常用資料結構操作。vector封裝陣列,list封裝了鍊錶,map和 set封裝了二叉樹等.
標準關聯容器set, multiset, map, multimap內部採用的就是一種非常高效的平衡檢索二叉樹:紅黑樹,也成為rb樹(red-blacktree)。rb樹的統計效能要好於一般的平衡二叉樹。
a. 為何map和set的插入刪除效率比用其他序列容器高?
答:因為對於關聯容器來說,不需要做記憶體拷貝和記憶體移動。map和set容器內所有元素都是以節點的方式來儲存,其節點結構和鍊錶差不多,指向父節點和子節點。
b. 為何每次insert之後,以前儲存的iterator不會失效?
答:iterator這裡就相當於指向節點的指標,記憶體沒有變,指向記憶體的指標怎麼會失效呢(當然被刪除的那個元素本身已經失效 了)。相對於vector來說,每一次刪除和插入,指標都有可能失效,呼叫push_back在尾部插入也是如此。因為為了保證內部資料的連續存 放,iterator指向的那塊記憶體在刪除和插入過程中可能已經被其他記憶體覆蓋或者記憶體已經被釋放了。即使時push_back的時候,容器內部空間可能 不夠,需要一塊新的更大的記憶體,只有把以前的記憶體釋放,申請新的更大的記憶體,複製已有的資料元素到新的記憶體,最後把需要插入的元素放到最後,那麼以前的內 存指標自然就不可用了。特別時在和find等演算法在一起使用的時候,牢記這個原則:不要使用過期的iterator。
c. 為何map和set不能像vector一樣有個reserve函式來預分配資料?
答:原因在於在map和set內部儲存的已經不是元素本身了,而是包含元素的節點。
set,multiset
set和multiset會根據特定的排序準則自動將元素排序,set中元素不允許重複,multiset可以重複。
因為是排序的,所以set中的元素不能被修改,只能刪除後再新增。
向set中新增的元素型別必須過載《操作符用來排序。排序滿足以下準則:
(1)非對稱,若a < b為真,則b < a為假。
(2)可傳遞,若a < b ,b < c,則a < c。
(3)a < a永遠為假。
set中判斷元素是否相等:if(!(a < b || b < a)),當a < b和b < a都為假時,它們相等。
map,multimap
map和multimap將key和value組成的pair作為元素,根據key的排序準則自動將元素排序,map中元素的key不允許重複,multimap可以重複。
map
因為是排序的,所以map中元素的key不能被修改,只能刪除後再新增。key對應的value可以修改。
向map中新增的元素的key型別必須過載《操作符用來排序。排序與set規則一致。
hash_map和map的區別在**?
建構函式。hash_map需要hash函式,等於函式;map只需要比較函式(小於函式).
儲存結構。hash_map採用hash表儲存,map一般採用 紅黑樹(rb tree) 實現。因此其memory資料結構是不一樣的。
什麼時候需要用hash_map,什麼時候需要用map?
總體來說,hash_map 查詢速度會比map快,而且查詢速度基本和資料資料量大小,屬於常數級別;而map的查詢速度是log(n)級別。並不一定常數就比log(n) 小,hash還有hash函式的耗時,明白了吧,如果你考慮效率,特別是在元素達到一定數量級時,考慮考慮hash_map。但若你對記憶體使用特別嚴格, 希望程式盡可能少消耗記憶體,那麼一定要小心,hash_map可能會讓你陷入尷尬,特別是當你的hash_map物件特別多時,你就更無法控制了,而且 hash_map的構造速度較慢。
現在知道如何選擇了嗎?權衡三個因素: 查詢速度, 資料量, 記憶體使用
vector, list, deque
(1).vector - 會自動增長的陣列
vector < int > vec(10) //乙個有10個int元素的容器
vector < float > vec(10, 0.5)//乙個有10個float元素的容器,並且他們得值都是0.5
vector ::iterator iter;
for(iter = vec.begin(); iter != vec.end(); iter++)
vector由於陣列的增長只能向前,所以也只提供了後端插入和後端刪除,
也就是push_back和pop_back。當然在前端和中間要運算元據也是可以的,
用insert和erase,但是前端和中間對資料進行操作必然會引起資料塊的移動,
這對效能影響是非常大的。
最大的優勢就是隨機訪問的能力。
vector::iterator相關的方法有:
begin():用來獲得乙個指向vector第乙個元素的指標
end():用來獲得乙個指向vector最後乙個元素之後的那個位置的指標,注意不是指向最後乙個元素。
erase(vector::iterator):用來刪除作為引數所傳入的那個iterator所指向的那個元素。
(2)list - 擅長插入刪除的鍊錶
listmilkshakes; listscores;
push_back, pop_backpush_front. pop_front
list是乙個雙向鍊錶的實現。
為了提供雙向遍歷的能力,list要比一般的資料單元多出兩個指向前後的指標
乙個使用iterator來刪除元素的例子
list stringlist;
list::iterator iter;
advance(iter, 5); //將iterator指向stringlist的第五個元素
stringlist.erase(iterator);//刪除
那麼刪除操作進行以後,傳入erase()方法的iterator指向**了呢?它指向了刪除操作前所指向的那個元素的後乙個元素。
(3)deque - 擁有vector和list兩者優點的雙端佇列.deque是雙端佇列可在頭和尾部插入、刪除元素。
(4)這三個模板的總結 比較和一般使用準則
這三個模板都屬於序列類模板,可以看到他們有一些通用方法
size():得到容器大小
begin():得到指向容器內第乙個元素的指標(這個指標的型別依容器的不同而不同)
end():得到指向容器內最後乙個元素之後乙個位置的指標
erase():刪除傳入指標指向的那個元素
clear():清除所有的元素
==運算子:判斷兩個容器是否相等
=運算子:用來給容器賦值
上面的三個模板有各自的特點
vector模板的資料在記憶體中連續的排列,所以隨機訪問元素(即通過運算子訪問)的速度最快,這一點和陣列是一致的。同樣由於它的連續排列,所以它在除尾部以外的位置刪除或新增元素的速度很慢,在使用vector時,要避免這種操作。
list模板的資料是鏈式儲存,所以不能隨機訪問元素。它的優勢在於任意位置新增 刪除元素的速度。
deque模板是通過鏈結若干片連續的資料實現的,所以均衡了以上兩個容器的特點
vector記憶體用完了,會以當前size大小重新申請2*size的記憶體,然後把原來的元素複製過去,把新元素插上,然後釋放原來的記憶體。
一般我們釋放vector裡的元素使用clear,其實它不能釋放記憶體,要想釋放記憶體要使用swap
map是怎麼實現的?查詢的複雜度是多少?能不能邊遍歷邊插入?
a. 紅黑樹和雜湊
b. o(logn)
c. 不可以,map不像vector,它在對容器執行erase操作後不會返回後乙個元素的迭代器,所以不能遍歷地往後刪除。
hash_map和map的區別在**?
hash_map底層是雜湊的所以理論上操作的平均複雜度是常數時間,map底層是紅黑樹,理論上平均複雜度是o(logn),下面是借鑑的網上的總結:
這 裡總結一下,選用map還是hash_map,關鍵是看關鍵字查詢操作次數,以及你所需要保證的是查詢總體時間還是單個查詢的時間。如果是要很多次操作, 要求其整體效率,那麼使用hash_map,平均處理時間短。如果是少數次的操作,使用 hash_map可能造成不確定的o(n),那麼使用平均處理時間相對較慢、單次處理時間恆定的map,考慮整體穩定性應該要高於整體效率,因為前提在操 作次數較少。如果在一次流程中,使用hash_map的少數操作產生乙個最壞情況o(n),那麼hash_map的優勢也因此喪盡了。
快排演算法的樞軸位置是怎麼選擇的?
三點中值法,取整個序列的頭、尾、**三個位置的元素,以其中值作為樞軸。
程序和執行緒的差別?
答:執行緒是指程序內的乙個執行單元,也是程序內的可排程實體.區別:
(1)排程:執行緒作為排程和分配的基本單位,程序作為擁有資源的基本單位
(2)併發性:不僅程序之間可以併發執行,同乙個程序的多個執行緒之間也可併發執行
(3)擁有資源:程序是擁有資源的乙個獨立單位,執行緒不擁有系統資源,但可以訪問隸屬於程序的資源.
(4)系統開銷:建立撤消程序,系統都要為之分配和**資源,系統的開銷明顯大於建立撤消執行緒
多程序與多執行緒,兩者都可以提高程式的併發度,提高程式執行效率和響應時間。
Linux面試常考知識點
同步 非同步 阻塞與非阻塞 推薦 linux 五種io模型 詳解 linux下五種io模型 關於select poll epoll詳細介紹 分析 select poll epoll 推薦 linux 下i o多路復用區別與優缺點 select poll epoll區別 附 linux多程序程式設計中...
前端面試常考知識點
1.css3的新特性有哪些 點我檢視 css3選擇器 css3邊框與圓角 css3圓角border radius 屬性值由兩個引數值構成 value1 value2,值之間用 分隔,value1代表圓角的水平半徑,value2代表圓角的垂直半徑 盒陰影box shadow 語法 box shadow...
前端面試常考知識點 CSS
前端面試常考知識點 js 點我檢視 css3選擇器 css3邊框與圓角 css3圓角border radius 屬性值由兩個引數值構成 value1 value2,值之間用 分隔,value1代表圓角的水平半徑,value2代表圓角的垂直半徑 盒陰影box shadow 語法 box shadow ...