STL容器底层数据结构的实现
C++ STL 的實現:
1.vector ?? ??底層數據結構為數組 ,支持快速隨機訪問 2.list ??? ??? ???底層數據結構為雙向鏈表,支持快速增刪 3.deque ??? ??底層數據結構為一個中央控制器和多個緩沖區,詳細見STL源碼剖析P146,支持首尾(中間不能)快速增刪,也支持隨機訪問 deque是一個雙端隊列(double-ended queue),也是在堆中保存內容的.它的保存形式如下: [堆1] -->?[堆2] -->[堆3] --> ... 每個堆保存好幾個元素,然后堆和堆之間有指針指向,看起來像是list和vector的結合品. 4.stack? ??? ??底層一般用list或deque實現,封閉頭部即可,不用vector的原因應該是容量大小有限制,擴容耗時 5.queue?? ??底層一般用list或deque實現,封閉頭部即可,不用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 容器
vector 的數據安排以及操作方式,與 array 非常相似。兩者的唯一區別在于空間的運用的靈活性。array 是靜態空間,一旦配置了就不能改變,vector 是動態數組,所以不支持前插操作。在堆上分配空間。vector 是動態空間,隨著元素的加入,它的內部機制會自行擴充空間以容納新元素(有保留內存,如果減少大小后內存也不會釋放。如果新值>當前大小時才會再分配內存,這大大影響了 vector 的效率,)。因此,vector 的運用對于內存的合理利用與運用的靈活性有很大的幫助,我們再也不必因為害怕空間不足而一開始要求一個大塊的 array。
vector 動態增加大小,并不是在原空間之后持續新空間(因為無法保證原空間之后尚有可供配置的空間),而是以原大小的兩倍另外配置一塊較大的空間,然后將原內容拷貝過來,然后才開始在原內容之后構造新元素,并釋放原空間。因此,對 vector 的任何操作,一旦引起空間重新配置,同時指向原vector 的所有迭代器就都失效了。
即:“因舊空間不足而重新配置一塊更大空間,然后復制元素,再釋放舊空間”
對最后元素操作最快(在后面添加刪除最快),此時一般不需要移動內存。對中間和開始處進行添加刪除元素操作需要移動內存。如果你的元素是結構或是類,那么移動的同時還會進行構造和析構操作,所以性能不高(最好將結構或類的指針放入 vector 中,而不是結構或類本身,這樣可以避免移動時的構造與析構)。訪問方面,對任何元素的訪問都是 O(1),也就是常數時間的。?
總結:
?vector 常用來保存需要經常進行隨機訪問的內容,并且不需要經常對中間元素進行添加刪除操作。
?
2、list 容器
相對于 vector 的連續空間,list 就顯得復雜許多,它的好處是每次插入或刪除一個元素,就配置或釋放一個元素空間,元素也是在堆中。因此,list 對于空間的運用有絕對的精準,一點也不浪費。而且,對于任何位置的元素插入或元素移除,永遠是常數時間。STL 中的list 底層是一個雙向鏈表,而且是一個環狀雙向鏈表。這個特點使得它的隨即存取變的非常沒有效率,因此它沒有提供 [] 操作符的重載。
總結:
如果你喜歡經常添加刪除大對象的話,那么請使用 list;
要保存的對象不大,構造與析構操作不復雜,那么可以使用 vector 代替。
list<指針> 完全是性能最低的做法,這種情況下還是使用 vector<指針> 好,因為指針沒有構造與析構,也不占用很大內存
?
3、deque 容器
deque 是一種雙向開口的連續線性空間,元素也是在堆中。所謂雙向開口,意思是可以在首尾兩端分別做元素的插入和刪除操作。deque 和 vector 的最大差異,一在于 deque 允許于常數時間內對起頭端進行元素的插入或移除操作,二在于deque沒有所謂容量觀念,因為它是動態地以分段連續空間組合而成,隨時可以增加一段新的空間并鏈接在一起。換句話說,像 vector 那樣“因舊空間不足而重新配置一塊更大空間,然后復制元素,再釋放舊空間”這樣的事情在 deque 是不會發生的。它的保存形式如下:
[堆1] --> [堆2] -->[堆3] --> ...deque 是由一段一段的定量連續空間構成。一旦有必要在 deque 的前端或尾端增加新空間,便配置一段定量連續空間,串接在整個 deque 的頭端或尾端。deque 的最大任務,便是在這些分段的定量連續空間上,維護其整體連續的假象,并提供隨機存取的接口。避開了“重新配置,復制,釋放”的輪回,代價則是復雜的迭代器架構。因為有分段連續線性空間,就必須有中央控制器,而為了維持整體連續的假象,數據結構的設計及迭代器前進后退等操作都頗為繁瑣。
deque 采用一塊所謂的 map 作為主控。這里的 map 是一小塊連續空間,其中每個元素都是指針,指向另一段連續線性空間,稱為緩沖區。緩沖區才是 deque 的存儲空間主體。(?底層數據結構為一個中央控制器和多個緩沖區)SGI STL 允許我們指定緩沖區大小,默認值 0 表示將使用 512 bytes 緩沖區。
支持[]操作符,也就是支持隨即存取,可以在前面快速地添加刪除元素,或是在后面快速地添加刪除元素,然后還可以有比較高的隨機訪問速度和vector 的效率相差無幾。deque 支持在兩端的操作:push_back,push_front,pop_back,pop_front等,并且在兩端操作上與 list 的效率也差不多。
在標準庫中 vector 和 deque 提供幾乎相同的接口,在結構上區別主要在于在組織內存上不一樣,deque 是按頁或塊來分配存儲器的,每頁包含固定數目的元素;相反 vector 分配一段連續的內存,vector 只是在序列的尾段插入元素時才有效率,而 deque 的分頁組織方式即使在容器的前端也可以提供常數時間的 insert 和 erase 操作,而且在體積增長方面也比 vector 更具有效率。
總結:
list 是可以快速地在所有地方添加刪除元素,但是只能快速地訪問最開始與最后的元素(不支持隨機訪問元素);
deque 在開始和最后添加元素都一樣快,并提供了隨機訪問方法,像vector一樣使用 [] 訪問任意元素,但是隨機訪問速度比不上vector快,因為它要內部處理堆跳轉。deque 也有保留空間。另外,由于 deque 不要求連續空間,所以可以保存的元素比 vector 更大,這點也要注意一下。還有就是在前面和后面添加元素時都不需要移動其它塊的元素,所以性能也很高。
因此在實際使用時,如何選擇這三個容器中哪一個,應根據你的需要而定,一般應遵循下面的原則:
1、如果你需要高效的隨機存取,而不在乎插入和刪除的效率,使用 vector;2、如果你需要大量的插入和刪除,而不關心隨即存取,則應使用 list;
3、如果你需要隨機存取,而且關心兩端數據的插入和刪除,則應使用deque。
?
4、stack
stack 是一種先進后出(First In Last Out , FILO)的數據結構。它只有一個出口,stack 允許新增元素,移除元素,取得最頂端元素。但除了最頂端外,沒有任何其它方法可以存取stack的其它元素,stack不允許遍歷行為。
以某種容器(?一般用 list 或 deque 實現,封閉頭部即可,不用 vector 的原因應該是容量大小有限制,擴容耗時)作為底部結構,將其接口改變,使之符合“先進后出”的特性,形成一個 stack,是很容易做到的。deque 是雙向開口的數據結構,若以 deque 為底部結構并封閉其頭端開口,便輕而易舉地形成了一個stack。因此,SGI STL 便以 deque 作為缺省情況下的 stack 底部結構,由于 stack 系以底部容器完成其所有工作,而具有這種“修改某物接口,形成另一種風貌”之性質者,稱為 adapter(配接器),因此,STL stack 往往不被歸類為 container(容器),而被歸類為 container adapter。
5、 queue
queue 是一種先進先出(First In First Out,FIFO)的數據結構。它有兩個出口,queue 允許新增元素,移除元素,從最底端加入元素,取得最頂端元素。但除了最底端可以加入,最頂端可以取出外,沒有任何其它方法可以存取 queue 的其它元素。
以某種容器(?一般用 list 或 deque 實現,封閉頭部即可,不用 vector 的原因應該是容量大小有限制,擴容耗時)作為底部結構,將其接口改變,使之符合“先進先出”的特性,形成一個 queue,是很容易做到的。deque 是雙向開口的數據結構,若以 deque 為底部結構并封閉其底部的出口和前端的入口,便輕而易舉地形成了一個 queue。因此,SGI STL 便以 deque 作為缺省情況下的 queue 底部結構,由于 queue 系以底部容器完成其所有工作,而具有這種“修改某物接口,形成另一種風貌”之性質者,稱為 adapter(配接器),因此,STL queue 往往不被歸類為container(容器),而被歸類為 container adapter。 stack 和 queue 其實是適配器,而不叫容器,因為是對容器的再封裝。?
6、heap
heap 并不歸屬于 STL 容器組件,它是個幕后英雄,扮演 priority queue(優先隊列)的助手。priority queue 允許用戶以任何次序將任何元素推入容器中,但取出時一定按從優先權最高的元素開始取。按照元素的排列方式,heap 可分為 max-heap 和 min-heap 兩種,前者每個節點的鍵值(key)都大于或等于其子節點鍵值,后者的每個節點鍵值(key)都小于或等于其子節點鍵值。因此, max-heap 的最大值在根節點,并總是位于底層array或vector的起頭處;min-heap 的最小值在根節點,亦總是位于底層array或vector起頭處。STL 供應的是 max-heap,用 C++ 實現。
堆排序 C++ 語言實現:點擊這里。
7、priority_queue
priority_queue 是一個擁有權值觀念的 queue,它允許加入新元素,移除舊元素,審視元素值等功能。由于這是一個 queue,所以只允許在底端加入元素,并從頂端取出元素,除此之外別無其它存取元素的途徑。priority_queue 帶有權值觀念,其內的元素并非依照被推入的次序排列,而是自動依照元素的權值排列(通常權值以實值表示)。權值最高者,排在最前面。缺省情況下 priority_queue 系利用一個 max-heap 完成,后者是一個以vector 表現的 complete binary tree.max-heap 可以滿足 priority_queue 所需要的“依權值高低自動遞減排序”的特性。
priority_queue 完全以底部容器(一般為vector為底層容器)作為根據,再加上 heap 處理規則,所以其實現非常簡單。缺省情況下是以 vector 為底部容器。queue 以底部容器完成其所有工作。具有這種“修改某物接口,形成另一種風貌“”之性質者,稱為 adapter(配接器),因此,STL priority_queue 往往不被歸類為 container(容器),而被歸類為 container adapter。
8、set?和?multiset?容器
set?的特性是,所有元素都會根據元素的鍵值自動被排序。set 的元素不像 map 那樣可以同時擁有實值(value)和鍵值(key),set 元素的鍵值就是實值,實值就是鍵值,set不允許兩個元素有相同的值。set 底層是通過紅黑樹(RB-tree)來實現的,由于紅黑樹是一種平衡二叉搜索樹,自動排序的效果很不錯,所以標準的 STL 的 set 即以 RB-Tree 為底層機制。又由于 set 所開放的各種操作接口,RB-tree 也都提供了,所以幾乎所有的 set 操作行為,都只有轉調用 RB-tree 的操作行為而已。
multiset的特性以及用法和 set 完全相同,唯一的差別在于它允許鍵值重復,因此它的插入操作采用的是底層機制是 RB-tree 的 insert_equal() 而非 insert_unique()。
9、map?和?multimap?容器
map的特性是,所有元素都會根據元素的鍵值自動被排序。map 的所有元素都是 pair,同時擁有實值(value)和鍵值(key)。pair 的第一元素被視為鍵值,第二元素被視為實值。map不允許兩個元素擁有相同的鍵值。由于 RB-tree 是一種平衡二叉搜索樹,自動排序的效果很不錯,所以標準的STL map 即以 RB-tree 為底層機制。又由于 map 所開放的各種操作接口,RB-tree 也都提供了,所以幾乎所有的 map 操作行為,都只是轉調 RB-tree 的操作行為。
?
multimap?的特性以及用法與 map 完全相同,唯一的差別在于它允許鍵值重復,因此它的插入操作采用的是底層機制 RB-tree 的 insert_equal() 而非 insert_unique。?
?
10、hash_set 和?hash_multiset?容器
?
hash_set?底層數據結構為 hash 表,無序,不重復。
?
hash_multiset?底層數據結構為 hash 表,無序,不重復。?
?
?
11、hash_map?和?hash_multimap?容器
hash_map?底層數據結構為 hash 表,無序,不重復。
?
hash_multimap?底層數據結構為 hash 表,無序,不重復。?
轉載于:https://www.cnblogs.com/FengZeng666/p/9347027.html
總結
以上是生活随笔為你收集整理的STL容器底层数据结构的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 货拉拉如何抢单更快
- 下一篇: 分布式全局ID生成器设计