容器

容器的概念所謂STL容器,即是將最常運用的一些數據結構(data structures)實現出來。容器是指容納特定類型對象的集合。根據數據在容器中排列的特性,容器可概分為序列式(sequence)和關聯式(associative)兩種。迭代器是一種檢查容器內元素并遍歷元素的數據類型。它提供類似指針的功能,對容器的內容進行走訪。#include例如:std::vectorIntVector;std::vector::iterator first = IntVector.begin();// begin()得到指向vector開頭的Iterator,*first得到開頭一個元素的值std::vector::iterator last = IntVector.end();// end()得到指向vector結尾的Iterator,*last得到最后一個元素的值序列式容器所謂序列式容器,其中的元素都可序(ordered),但未必有序(sorted)。數組為C++語言內置的序列容器,STL另外提供vector、list、deque(double - ended queue)。它們的差別在于訪問元素的方式,以及添加或刪除元素相關操作的運行代價。標準庫還提供了三種容器適配器(adapter),所謂適配器是根據原始的容器類型所提供的操作,通過定義新的操作接口,來適應基礎的容器類型。順序容器適配器包括stack、queue、priority_queue等序列式容器。其中stack和queue由于只是將deque改頭換面而成,技術上被歸類為一種配接器(adapter),priority_queue是有優先級管理的隊列。一.Vector1.vector的基本概念vector是標準C++建議替代C數組的動態數組模型,它維護的是一個連續線性空間。vector所采用的數據結構非常簡單:線性連續空間。它以兩個迭代器start和finish分別指向配置得到的連續空間中目前已被使用的范圍,并以迭代器end_of_storage指向整塊連續空間(含備用空間)的尾端。vector的實現技術,關鍵在于其對大小的控制以及重新分配時的數據移動效率。一旦vector原有空間用完,如果客戶端每新增一個元素,vector內部就只擴充一個元素的空間,實為不智。因為所謂擴充控件(不論多大),是“配置新空間(malloc) / 拷貝移動數據(memcpy) / 釋放舊空間(free)”的大工程,時間成本很高,應該采用某種未雨綢繆的空間配置策略。注意,所謂動態增加大小,并不是在原空間之后接續新空間(因為無法保證之后尚有可供配置的空間),而是每次再分配原大小兩倍的內存空間。因此,對vector的任何操作,一旦引起控件重新配置,指向原vector的所有迭代器就都失效了。由于vector維護的是一個連續線性空間,因此vector迭代器具備普通指針的功能,支持隨機存取,即vector提供的是Random Access Iterators。2.向量類模板std::vector的成員函數#includestd::vectorvec;std::vectorvec(size);std::vectorvec(size, value);std::vectorvec(myvector);std::vectorvec(first, last);Operators: == 、 != 、 <= 、 >= 、<、>、[]assign(first, last):用迭代器first, last所指定的元素取代向量元素assign(num, val):用val的num份副本取代向量元素at(n):等價于[]運算符,返回向量中位置n的元素,因其有越界檢查,故比[]索引訪問安全front():返回向量中第一個元素的引用back():返回向量中最后一個元素的引用begin():返回向量中第一個元素的迭代器end():返回向量中最后一個元素的下一個迭代器(僅作結束游標,不可解引用)max_size():返回向量類型的最大容量(2 ^ 30 - 1 = 0x3FFFFFFF)capacity():返回向量當前開辟的空間大小( <= max_size,與向量的動態內存分配策略相關)size():返回向量中現有元素的個數( <= capacity)clear():刪除向量中所有元素empty():如果向量為空,返回真erase(start, end):刪除迭代器start end所指定范圍內的元素erase(i):刪除迭代器i所指向的元素erase()返回指向刪除的最后一個元素的下一位置的迭代器insert(i, x);把x插入到迭代器i所指定的位置之前insert(i, n, x):把x的n份副本插入到迭代器i所指定的位置之前insert(i, start, end):把迭代器start和end所指定的范圍內的值插入到迭代器i所指定的位置之前push_back(x):把x推入(插入)到向量的尾部pop_back():彈出(刪除)向量最后一個元素rbegin():返回一個反向迭代器,該迭代器指向的元素越過了向量中的最后一個元素rend():返回一個反向迭代器,該迭代器指向向量中第一個元素reverse():反轉元素順序resize(n, x):把向量的大小改為n, 新元素的初值賦為xswap(vectorref):交換2個向量的內容3.動態字符串類std::stringstring是標準C++建議替代C字符串(以零結束的字符數組)的動態字符串模型,可以簡單的看做vector。#includestd::string str1;std::string str3(str2);std::string str2("this is a string");以下未列出與vector相同的通用操作。Operators: + 、 +=length():和size()函數功能相同data():取得字符串指針c_str():取得C風格字符串指針c_str()的流程是先調用terminate(),然后再返回data()。因此如果你對效率要求比較高,而且你的處理又不一定需要以 / 0的方式結束,最好選擇data()。但是對于一般的C函數中,需要以const char*為輸入參數,要使用c_str()函數。operator=:賦值操作符append():追加字符串replace():替換字符copy():拷貝自己的num個字符到str中(從索引index開始)。find():在字符串中查找指定字符, 返回基于0的索引號rfind():反向查找find_first_of():查找包含子串中的任何字符,返回第一個位置find_first_not_of():查找不包含子串中的任何字符,返回第一個位置find_last_of():查找包含子串中的任何字符,返回最后一個位置find_last_not_of():查找不包含子串中的任何字符,返回最后一個位置substr(n1, len):得到字符串從n1開始的長度為len的子串比較字符串(支持所有的關系運算符)compare 比較字符串operator+? 字符串銜接operator+= 增加操作符operator== 判斷是否相等operator!= 判斷是否不等于operator< 判斷是否小于operator>> 從輸入流中讀入字符串operator<< 字符串寫入輸出流getline 從輸入流中讀入一行二.list1.list的基本概念相對于vector的連續線性空間,list就顯得復雜許多,與向量(vector)相比, 它允許快速的插入和刪除,且每次插入或刪除一個元素,就配置或釋放一個元素空間。因此,list對于空間的運用絕對的精準,一點也不浪費。而且,對于任何位置的元素插入或元素移除,list永遠是常數時間。list不再能夠像vector那樣以普通指針作為迭代器,因為其節點不保證在儲存空間中連續存在。list迭代器必須有能力指向list的節點,并有能力進行正確的遞增、遞減、取值、成員存取等操作。所謂“list迭代器正確的遞增、遞減、取值、成員取用”操作是指,遞增時指向下一個節點,遞減時指向上一個節點,取值時取的是節點的數據值,成員取用時取用的是節點的成員。list不僅是一個雙向鏈表,而其還是一個環狀雙向鏈表。所以它只需要一個指針,便可以完整實現整個鏈表。由于list是一個雙向鏈表(double linked - list),迭代器必須具備前移、后移的能力,所以list提供的是Bidirectional Iterators。list有一個重要性質:插入操作(insert)和合并操作(splice)都不會造成原有的list迭代器失效。這在vector是不成立的,因為vector的插入操作可能造成記憶體重新配置,導致原有的迭代器全部失效。甚至list的元素刪除操作(erase)也只有“指向被刪除元素”的那個迭代器失效,其他迭代器不受任何影響。2.鏈表類模板std::list成員函數#includestd::listlst;std::listlst(size);std::listlst(size, value);std::listlst(mylist);std::listlst(first, last);以下未列出與vector相同的通用操作。push_front(x):把元素x推入(插入)到鏈表頭部pop_front():彈出(刪除)鏈表首元素merge(listref):把listref所引用的鏈表中的所有元素插入到鏈表中,可指定合并規則splice():把lst連接到pos的位置remove(val):刪除鏈表中所有值為val的元素remove_if(pred):刪除鏈表中謂詞pred為真的元素(謂詞即為元素存儲和檢索的描述,如std::less<>,std::greater<>那么就按降序 / 升序排列,你也可以定義自己的謂詞)sort():根據默認的謂詞對鏈表排序sort(pred):根據給定的謂詞對鏈表排序unique():刪除鏈表中所有重復的元素unique(pred):根據謂詞pred刪除所有重復的元素,使鏈表中沒有重復元素注意:vector和deque支持隨機訪問,而list不支持隨機訪問,因此不支持[]訪問!三.deque1.deque的基本概念vector是單向開口的連續線性空間,deque則是以中雙向開口的連續線性空間。所謂雙向開口,意思是可以在頭尾兩端分別做元素的插入和刪除操作。從技術的角度而言,vector當然也可以在頭尾兩端進行操作,但是其頭部操作效率奇差、令人無法接受。deque和vector的最大差異,一在于deque允許于常數時間內對頭端進行元素的插入或移除操作,二在于deque沒有所謂容量(capacity)觀念,因為它是動態地以分段連續空間組合而成,隨時可以增加一段新的空間并鏈接起來。換句話說,像vector那樣“因舊空間不足而重新配置一塊更大空間,然后復制元素,再釋放舊空間”這樣的事情在deque中是不會發生的。也因此,deque沒有必要提供所謂的空間預留(reserved)功能。雖然deque也提供Random Access Iterator,但它的迭代器并不是普通指針,其復雜度和vector不可同日而語,這當然涉及到各個運算層面。因此,除非必要,我們應盡可能選擇使用vector而非deque。對deque進行的排序操作,為了最高效率,可將deque先完整復制到一個vector身上,將vector排序后(利用STL的sort算法),再復制回deque。deque是由一段一段的定量連續空間構成。一旦有必要在deque的前端或尾端增加新空間,便配置一段定量的連續空間,串接在整個deque的頭端或尾端。deque的最大任務,便是在這些分段的定量連續空間上,維護其整體連續的假象,并提供隨機存取的接口。避開了“重新配置、復制、釋放”的輪回,代價則是復雜的迭代器架構。2.雙端隊列類模板std::deque成員函數#includestd::dequedeq;std::dequedeq(size);std::dequedeq(size, value);std::dequedeq(mydeque);std::dequedeq(first, last);其成員函數如下:Operators:[]用來訪問雙向隊列中單個的元素front():返回第一個元素的引用push_front(x):把元素x推入(插入)到雙向隊列的頭部pop_front():彈出(刪除)雙向隊列的第一個元素back():返回最后一個元素的引用push_back(x):把元素x推入(插入)到雙向隊列的尾部pop_back():彈出(刪除)雙向隊列的最后一個元素四.基于deque的順序容器適配器stack、queue(priority_queue)stack1.stack的基本概念stack是一種后進先出(First In Last Out,FILO)的數據結構,它只有一個出口。stack允許新增元素、移除元素、取得最頂端元素。但除了最頂端外,沒有任何其他方法可以存取stack的其他元素,換言之,stack不允許隨機訪問。STL以deque作為stack的底層結構,對deque封閉期頭端開口,稍作修改便形成了stack。將元素插入stack的操作稱為push,將元素彈出stack的操作稱為pop。stack所有元素的進出都必須符合“后進先出”的條件,只有stack頂端的元素,才有機會被外界取用。stack不提供走訪功能,也不提供迭代器。2.容器適配器堆棧類std::stack成員函數#includestack實現后進先出的操作std::stackstk;type為堆棧操作的數據類型container為實現堆棧所用的容器類型,默認基于deque,還可以為std::vector和std::list例如std::stack> IntStack;其成員函數如下:top():返回頂端元素的引用push(x):將元素壓入棧(頂)pop():彈出(刪除)頂端元素queue1.queue的基本概念queue是一種先進先出(First In First Out,FIFO)的數據結構,它有兩個出口。queue允許新增元素、移除元素、從最底端加入元素、取得最頂端元素。但除了最底端可以加入、最頂端可以取出,沒有任何其他方法可以存取queue的其他元素。換言之,queue不支持隨機訪問。STL以deque作為queue的底層結構,對deque封閉其底端的出口和前端的入口,稍作修改便形成了queue。2.容器適配器隊列類std::queue成員函數#includequeue實現先進先出的操作std::queueque;type為隊列操作的數據類型container為實現隊列所用的容器類型,只能為提供了push_front操作的std::deque或std::list,默認基于std::deque其成員函數如下:front():返回隊首元素的引用back():返回隊尾元素的引用push(x):把元素x推入(插入)到隊尾pop():隊首元素出列(彈出(刪除)隊首元素)priority_queue1.priority_queue的基本概念priority_queue為優先級隊列,它允許用戶為隊列中存儲的元素設置優先級。這種隊列不是直接將新元素放置在隊列尾部,而是放置在比它優先級低的元素前面,即提供了一種插隊策略。標準庫默認使用<操作符來確定他們之間的優先級關系。即權重大的排在隊首。使用priority_queue時,包含文件。2.容器適配器隊列類std::priority_queue成員函數#includepriority_queue實現先進先出的操作std::priority_queuepri_que;type為隊列操作的數據類型container為實現隊列所用的容器類型,可以為std::vector, std::deque,默認基于dequecomp為排隊策略,默認為std::less<>,即插到小于它的元素前例如std::priority_queue, std::greater> IntPriQue;其成員函數如下:top():返回隊首(優先級最高)元素的引用push(x):將元素推入(按插隊策略插排)隊列(尾部)pop():彈出(刪除)隊首(優先級最高)元素關聯式容器所謂關聯式容器,概念上類似關聯式數據庫(實際上則簡單許多):每項數據(元素)包含一個鍵值(key)和一個實值(value)。當元素被插入到關聯式容器中時,容器內部數據結構(可能是RB - tree,也可能是hash - table)便依照其鍵值大小,以某種特定規則將這個元素放置于適當位置。關聯式容器沒有所謂頭尾(只有最大元素和最小元素),所以不會有push_back(),push_front(),pop_back(),pop_front(),begin(),end()這樣的操作。一般而言,關聯式容器的內部結構是一個balanced binary tree(平衡二叉樹),以便獲得良好的搜索效率。balanced binary tree有很多種類型,包括AVL - tree、RB - tree、AA - tree,其中廣泛運用于STL的是RB - tree(紅黑樹)。標準的STL關聯式容器分為set(集合)和map(映射類)兩大類,以及這兩大類的衍生體multiset(多鍵集合)和multimap(多鍵映射表)。這些容器的底層機制均以RB - tree完成(紅黑樹)。RB - tree也是一個獨立容器,但并不開放給外界使用。此外,SGI STL還提供了一個不在標準規格之列的關聯式容器:hash table(散列表,哈希表),以及以此hash table為底層機制而完成的hash_set(散列集合)、hash_map(散列映射表)、hash_multiset(散列多鍵集合)、hash_multimap(散列多鍵映射表)。map關聯式容器std::map成員函數#includemap建立key - value映射std::mapmp;std::mapmp;

key為鍵值

value為映射值

comp可選,為鍵值對存放策略,例如可為std::less<>,鍵值映射對將按鍵值從小到大存儲

其成員函數如下:

count():返回map中鍵值等于key的元素的個數

equal_range():函數返回兩個迭代器——一個指向第一個鍵值為key的元素,另一個指向最后一個鍵值為key的元素

erase(i):刪除迭代器所指位置的元素(鍵值對)

lower_bound():返回一個迭代器,指向map中鍵值 >= key的第一個元素

upper_bound():函數返回一個迭代器,指向map中鍵值>key的第一個元素

find(key):返回鍵值為key的鍵值對迭代器,如果沒有該映射則返回結束游標end()

注意map的[]操作符,當試圖對于不存在的key進行引用時,將新建鍵值對,值為空。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容