STL容器分類

http://www.360doc.com/content/12/0705/08/6828497_222338600.shtml

容器(container)是裝有其他對象的對象。容器裏面的對象必須是同一類型,該類型必須是可拷貝構造和可賦值的,包括內置的基本數據類型和帶有公用拷貝構造函數和賦值操作符的類。典型的容器有隊列、鏈表和向量等。

在標準C++中,容器一般用模版類來表示。不過STL不是面嚮對象的技術,不強調類的層次結構,而是以效率和實用作爲追求的目標。所以在STL並沒有一個通用的容器類,各種具體的容器也沒有統一的基類。

容器可以視爲是數組的推廣,即對象的數組(廣義數組),其中的元素(對象)可以用下標(索引)來訪問。

容器的設計有兩條準則:一是在各個容器的設計中,提供儘可能大的自由度;二是使各 種容器能夠向用戶呈現出一個公共的界面/接口。目的是,使容器的實現能達到最佳效率,同時也使用戶能寫出不依賴於所使用的特定容器類型的通用代碼。容器的 設計通常只能滿足這兩條中的一條,但是STL卻提供了一個同時具有通用性和執行效率的解決方案。

標準C++的STL框架中的容器主要有兩大類:

l         序列容器(sequence container順序容器)—— 將一組具有相同類型T的對象,以嚴格的線性形式組織在一起。序列容器可以視爲數組和鏈表的推廣。STL中的序列容器有3種:

n         vector<T>(向量)——提供對變長序列的快速隨機訪問 (即對第i個元素的訪問時間,是與i無關的常量),對序列末尾的插入和刪除操作的時間是分攤常量;(似變長數組)(對應於vector類,定義在<vector>頭文件中);

n         deque<T>(double-ended queue雙端隊列)—— 提供對變長序列的快速隨機訪問,對序列頭尾的插入和刪除操作的時間都是分攤常量;(似雙向變長數組)(對應於deque類,定義 在<deque>頭文件中);

n         list<T>(表)—— 提供對變長序列的線性時間訪問(O(N),N爲序列的當前長度),但是在序列的任意位置的插入和刪除操作均爲常量時間。(似雙向鏈表)(對應於list類,定義在<list>頭文件中)。

l         關聯容器(associative container聯合容器)—— 關聯容器的特點是(鍵)有序的,即元素是按預定義的鍵順序(如升序)插入的。關聯容器具有從基於鍵的集 閤中快速提取對象的能力,其中集合的大小在運行時是可變的。關聯容器可以視爲關聯數組、映射或字典的推廣,它們保存的都是值的對偶,給定了其中的一個被稱 爲鍵(key)的值,就可以快速訪問與其對偶的另一個被稱爲映射值(mapped value)的值。STL中的關聯容器有4種:

n         set<Key>(集合)—— 支持唯一鍵值,並提供對鍵本身的快速檢索;例如set<long>:{學號}(對應於set類,定義在<set>頭文件中);

n         multiset<Key>(多重集合)—— 支持可重複鍵值,並提供對鍵本身的快速檢索;例如set<string>:{姓名}(可能有同名的)(對應於multiset類,也定義在<set>頭文件中);

n         map<Key, T>(映射/映像)—— 支持唯一Key類型的鍵值,並提供對另一個基於鍵的類型T的快速檢索;例如map<long, string>:{(學號, 姓名)}、{(電話號碼, 姓名)}等(對應於map類,定義在<map>頭文件中);

n         multimap<Key, T>(多重映射)—— 支持可重複Key類型的鍵值,並提供對另一個基於鍵的類型T的快速檢索;例如map<string, string>:{(姓名, 地址)}、{(姓名, 年齡)}等(對應於multimap類,也定義在<map>頭文件中)。

爲了改進搜索的時間,有些編譯器(包括VC2005)增加了4種對應的散列(hash)關聯容器類型:

n         hash_set<Key, H>(散列集)(對應於hash_set類,定義在<hash_set>頭文件中)

n         hash_multiset<Key, H>(散列多集)(對應於hash_multiset類,也定義在<hash_set>頭文件中)

n         hash_map<Key, T, H>(散列映射)(對應於hash_map類,定義在<hash_map>頭文件中)

n         hash_multimap<Key, T, H>(散列多映射)(對應於hash_multimap類,也定義在<hash_map>頭文件中)

 

除了這兩大類容器外,STL還有另外兩大類容器:

l         容器適配器(container adapter)—— 不是獨立的容器,只是某種容器的變種,它提供原容器的一個專用的受限接口。特別是,容器適配器不提供迭代器。在STL中有3種容器適配器:

n         stack<T>(棧)—— 只支持top()(讀取棧頂元素)、push()(在棧頂處加入新元素)和pop()(取出棧頂元素)操作(先入後出)的一種序列容器。可以是對任意一種 序列容器(缺省爲雙端隊列deque)的限制實現:刪除非棧操作,將原來序列容器的標準操作back()、push_back()和pop_back() 重新命名爲top()、push()和pop()。(對應於stack類,定義在<stack>頭文件中);

n         queue<T>(隊列)—— 與stack類似,queue也是對序列容器(缺省也爲雙端隊列deque)的限制實現。與棧相比,隊列也支持back()(讀取隊尾處的元素)和 push_back()(在隊尾處插入新元素)操作,但是不再支持pop_back()(取出隊尾處的元素)操作。不過,隊列卻允許front()(讀取 隊首處的元素)和pop_front()(取出隊首處的元素)操作(前出後入)。由於矢量vector容器不支持pop_front()操作,所以不能作 爲隊列queue的基礎容器。與前後都可出入的雙端隊列deque相比,隊列queue缺少push_front()和pop_back()操作。(對應 於queue類,定義在<queue>頭文件中);

n         priority_queue<T>(優先隊列)—— 也是一種隊列queue,不過其中的每個元素都被給定了一個優先級,用來控制元素到達隊首top()的順序。默認情況下,優先隊列簡單地使用運算 符<進行元素比較,top()返回最大的元素。注意,優先隊列,並不要求其全部元素都是有序的,而只要求其第一個元素是最大的。(對應於 priority_queue類,也定義在<queue>頭文件中)。

l         似容器(almost container擬容器)—— 在許多情況下可視爲容器,但是又缺乏標準容器界面的某些方面和特性,不能與開發完全的容器進行全面互換。除了內置數組外,STL中的似容器有3種:

n         string(串)—— 是實例化模版類basic_string<char>的類型定義typedef(另一個常用的wstring類,則是實例化模版類 basic_string<wchar_t>的類型定義typedef)。基本串basic_string提供下標操作、隨機訪問迭代器和其 他序列容器的幾乎所有功能,但是它不像容器那樣支持廣泛的元素類型選擇,而且它還爲作爲字符串使用而進行了優化,所以其典型使用方式與容器有着顯著差 異。(對應於string類,定義在<string>頭文件中)。有關string的更詳細內容,會在本節後面的4.3)中介紹;

n         valarray<T>(值數組)—— 是爲數值計算而進行了優化的向量,並不是一個具有通用性的容器。valarray提供了許多有用的數值運算和常用的數學函數,但是它只提供了標準容器操作 中的size()和下標操作,此外,其中元素的指針是一種隨機迭代器。(對應於valarray類,定義在<valarray>頭文件中);

n         bitset<N>(位集)—— 是標誌位字段的擴展,它通過提供在N個二進制位的集合(下標0~N-1)上的各種操作,使對標誌位的運算更爲方便。bitset可視爲一個N位的二進制 數,位取值0/1代表真假或開關,每一位從低位向高位進行編號。(對應於bitset類,定義在<bitset>頭文件中)。


  STL是C/C++開發中一個非常重要的模板,而其中定義的各種容器也是非常方便我 們大家使用。下面,我們就淺談某些常用的容器。這裏我們不涉及容器的基本操作之類,只是要討論一下各個容器其各自的特點。STL中的常用容器包括:順序性 容器(vector、deque、list)、關聯容器(map、set)、容器適配器(queue、stac)。

1、順序性容器

(1)vector

  vector是一種動態數組,在內存中具有連續的存儲空間,支持快速隨機訪問。由於具有連續的存儲空間,所以在插入和刪除操作方面,效率比較 慢。vector有多個構造函數,默認的構造函數是構造一個初始長度爲0的內存空間,且分配的內存空間是以2的倍數動態增長的,即內存空間增長是按照20,21,22,23..... 增長的,在push_back的過程中,若發現分配的內存空間不足,則重新分配一段連續的內存空間,其大小是現在連續空間的2倍,再將原先空間中的元素復 制到新的空間中,性能消耗比較大,尤其是當元素是非內部數據時(非內部數據往往構造及拷貝構造函數相當複雜)。vector的另一個常見的問題就是 clear操作。clear函數只是把vector的size清爲零,但vector中的元素在內存中並沒有消除,所以在使用vector的過程中會發現 內存消耗會越來越多,導致內存泄露,現在經常用的方法是swap函數來進行解決:  vector<int> V;
    V.push_back(1); V.push_back(2);V.push_back(1); V.push_back(2);
    vector<int>().swap(V); 或者 V.swap(vector<int>());
  利用swap函數,和臨時對象交換,使V對象的內存爲臨時對象的內存,而臨時對象的內存爲V對象的內存。交換以後,臨時對象消失,釋放內存。
    (2)deque

  deque和vector類似,支持快速隨機訪問。二者最大的區別在於,vector只能在末端插入數據,而deque支持雙端插入數據。 deque的內存空間分佈是小片的連續,小片間用鏈表相連,實際上內部有一個map的指針。deque空間的重新分配要比vector快,重新分配空間 後,原有的元素是不需要拷貝的。

(3)list

  list是一個雙向鏈表,因此它的內存空間是可以不連續的,通過指針來進行數據的訪問,這使list的隨機存儲變得非常低效,因此list沒有提供[]操作符的重載。但list可以很好地支持任意地方的插入和刪除,只需移動相應的指針即可。

(4)在實際使用時,如何選擇這三個容器中哪一個,應根據你的需要而定,一般應遵循下面的原則:
    1) 如果你需要高效的隨即存取,而不在乎插入和刪除的效率,使用vector
    2) 如果你需要大量的插入和刪除,而不關心隨即存取,則應使用list
    3) 如果你需要隨即存取,而且關心兩端數據的插入和刪除,則應使用deque

2、關聯容器

(1)map

  map是一種關聯容器,該容器用唯一的關鍵字來映射相應的值,即具有key-value功能。map內部自建一棵紅黑樹(一種自平衡二叉樹),這棵樹具有數據自動排序的功能,所以在map內部所有的數據都是有序的,以二叉樹的形式進行組織。這是map的模板:
       template < class Key, class T, class Compare= less<Key>, class Allocator=allocator< pair<const Key,T> > > class map;
從模板中我們可以看出,再構造map時,是按照一定的順序進行的。map的插入和刪除效率比其他序列的 容器高,因爲對關聯容器來說,不需要做內存的拷貝和移動,只是指針的移動。由於map的每個數據對應紅黑樹上的一個節點,這個節點在不保存你的數據時,是 佔用16個字節的,一個父節點指針,左右孩子指針,還有一個枚舉值(標示紅黑色),所以map的其中的一個缺點就是比較佔用內存空間。

(2)set

  set也是一種關聯性容器,它同map一樣,底層使用紅黑樹實現,插入刪除操作時僅僅移動指針即可,不涉及內存的移動和拷貝,所以效率比較高。 set中的元素都是唯一的,而且默認情況下會對元素進行升序排列。所以在set中,不能直接改變元素值,因爲那樣會打亂原本正確的順序,要改變元素值必須 先刪除舊元素,再插入新元素。不提供直接存取元素的任何操作函數,只能通過迭代器進行間接存取。set模板原型:
      template <class Key, class Compare=class<Key>, class Alloc=STL_DEFAULT_ALLOCATOR(Key) > class set;
  set支持集合的交(set_intersection)、差(set_difference)、並(set_union)及對稱差(set_symmetric_difference) 等一些集合上的操作。

3、容器適配器

(1)queue

  queue是一個隊列,實現先進先出功能,queue不是標準的STL容器,卻以標準的STL容器爲基礎。queue是在deque的基礎上封 裝的。之所以選擇deque而不選擇vector是因爲deque在刪除元素的時候釋放空間,同時在重新申請空間的時候無需拷貝所有元素。其模板爲:
    template < TYPENAME _Sequence="deque<_TP" typeneam _Tp,> > class queue;

(2)stack

  stack是實現先進後出的功能,和queue一樣,也是內部封裝了deque,這也是爲啥稱爲容器適配器的原因吧(純屬猜測)。自己不直接維護被控序列的模板類,而是它存儲的容器對象來爲它實現所有的功能。stack的源代碼原理和實現方式均跟queue相同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章