在進入stl的世界之前,我們先對其中的主要元件做一個鳥瞰:
先來一張層次圖:
如果覺得層次圖看不清的話,我們把它重新繪成思維導圖吧:
從圖中我們可以看到:
stl的核心隻有三個大元件:
容器
疊代器
算法
當然,這麼大的一個包羅萬象的c++标準庫,還是有很多其他的元件,比如智能指針、字元串、正規表達式、流式i/o、并發處理等不是跟容器相關的。但是做為核心的容器庫,就隻有這三大元件。
容器的種類其實蠻少的,大體上分為基本容器和特殊容器兩大類。
基本容器按照無序,有序,排序分成了三大類:
有序是需要排照一定的順序通路,比如數組和連結清單,但是并沒有根據元素的值進行排序。這樣的容器隻有5個:array數組,vector動态數組,deque兩端都可插入的動态數組,list雙向連結清單,forward_list單向連結清單。
排序是經過比較和排序算法處理之後的針對值也有序的結果。一共有4個,set集合,multiset值可重複集合,map不重複的鍵-值對,multimap鍵值可重複的map. 排序結構一般用排序二叉樹等結構來實作。
無序就是我們根本不關心元素的順序,我們隻關心是否放到容器中了。unordered set才是我們心目中的集合,不用加元素就排序。unordered multiset可以放多次。unordered map可以用作哈希表。unordered multimap可以用作字典。
隻有上面13種基本容器,還是非常簡單的。比起java來,功能上還是有所欠缺的,比如java中有對于并發支援比較好的concurrenthashmap,copyonwritearraylist等的複雜性就不是這些容器所能比的。相比來說,c++ stl中的容器還處于初級階段。
所謂疊代器,大家都熟悉疊代模式,就是周遊容器元素的方法。最簡單的用法就像是指針一樣,用*運算符取内容,++移至下一項,=指派,==和!=判斷是否相等。多出的begin()和end()是因為容器的通路需要一個頭和尾。cbegin()和cend()是c++11新引入的,用于常量表示的頭和尾。
最後是各種算法,小到計數,指派,大到所有元素排序。看起來不少,但是都是實際對容器操作用得上的,是以其實也并不多。
array在tr1才被加入到stl的大家庭中。其實它本質上就是個數組,無法增加新成員,隻能修改現有的成員的值。c++11為array帶來的就是可以支援統一初始化,我們來看一個例子:
和數組一樣,array通過[]運算符來通路。
下面,我們讓疊代器出場,看看用疊代器的方式如何周遊array:
第一個元素是array.begin(),最後一個元素是array.end(),取下一個元素用++運算符。c++11的auto又在這時刻發揮了作用,有了它,我們根本不需要知道疊代器的存在。管它是什麼呢,反正++可以取下一個,*可以擷取目前的值。一般情況下已經足夠用了。
下面,c++11又為我們送上一份小禮物,簡便寫法。大家直接看例程吧:
沒錯,連begin()和end()這樣的疊代函數和++,*這樣的運算符都給封裝起來了,我們拿到手的時候,已經是一個元素,在本例中就是個字元串。
我們再将算法應用到array容器,給容器做個排序:
輸出之後的結果就是對結果進行排序之後的了,如下:
忍受了固定大小的array之後,我們請向後擴充的數組vector粉墨登場。
vector的特點就是,在後面添加元素,也就是push_back函數的性能好。但是在前面和中間的性能就要引起其後的元素向後移動。
我們來個push_back的例子:
疊代器和算法的用法和array一模一樣:
deque是既可以在後面push_back,也可以在前面加元素push_front.
疊代和算法使用,還是跟array和vector都一樣。
list的能力更強了,不但支援push_back和push_front,還支援中間插入insert,可以在疊代器的某個位置之前插入元素。
單向連結清單forward list的能力在list的基礎上反而是受到了限制,隻能向前,不能向後。是以在forward list中是沒有push_back函數的。
set通常使用紅黑樹來實作。
有序結構不是存儲順序的結構,是以push_back之類的就沒有意義了,隻要有個insert就可以了。
而unordered_set通常采用哈希表來實作。
但是集合元素值一旦放進去,就不能直接修改了,否則排序就會亂掉。
我們來看個例子:
輸出是這樣的:
從上面的輸出可以看到,set是嚴格按字母順序排序的。而unordered_set就沒有這麼講究了,map還排在multiset之後。
元素可以重複,其餘跟集合基本一緻。
其實跟集合差不多,就是把元素換成std::pair了而己。
我們來看例子:
輸出如下:
map是嚴格按key值排序的,而unordered_map這個哈希表當然就沒有這麼嚴格了。
值重複的排序樹和哈希表,就不多說了。
我們用這麼少的篇幅,其實已經把stl的主要容器都給大家介始完了。同時,大家也體會到了疊代器和算法的作用。是以大家應該有信心,我們是可以學完整個c++标準庫的。
常用容器:
vector:變長數組,用push_back增加新元素。
list:雙向連結清單,可以使用push_back,push_front和insert
unordered_set:集合,insert元素
unordered_map:哈希表,insert std::pair
經常要用到排序的,就用set或者map。
有兩端操作需求的,可以用deque,它支援push_back和push_front,但是不支援insert。
要求元素重複的,記得set和map都有重複元素版本。
c++11提供了改進的for循環,可以很好地包裝疊代器。
算法是操作容器的通用工具。
最後小小補充一下算法的思想,它是跟面向對象設計的思想是完全相反的。oop的思想是将對象的屬性和函數封裝在一起,形成對象。但是算法的思想是與容器對象無關,将通用的操作抽象出來。
好了,這講就這麼多。