一、前言
STL:Standard Template Library(標(biāo)準(zhǔn)模板庫(kù)或泛型庫(kù)),是C++標(biāo)準(zhǔn)庫(kù)的組成部分。STL借助模板把常用的數(shù)據(jù)結(jié)構(gòu)及其算法實(shí)現(xiàn)了一次,并且做到了數(shù)據(jù)結(jié)構(gòu)和算法的分離。STL已完全被內(nèi)置到支持 C++ 的編譯器中,無(wú)需額外安裝,這可能也是STL被廣泛使用的原因之一。STL是以源代碼的形式提供的。根本上來(lái)說(shuō),STL是一些容器(封裝有數(shù)據(jù)結(jié)構(gòu)的模板類(lèi))、算法和其他的一些組件的集合,基本達(dá)到了各種存儲(chǔ)方法和相關(guān)算法的高度優(yōu)化。
STL的版本
HP STL
Alexandar Stepanov(STL 標(biāo)準(zhǔn)模板庫(kù)之父)與 Meng Lee 合作完成。是開(kāi)放源碼的。
SGI STL
HP STL的一個(gè)繼承版本,開(kāi)源、可讀性好
STLport
為了使 SGI STL 的基本代碼都適用于 VC++ 和 C++ Builder 等多種編譯器而提出的,開(kāi)源
PL STL
參照 HP STL 實(shí)現(xiàn)出來(lái)的,也是 HP STL 的一個(gè)繼承版本,因此該頭文件中不僅含有 HP STL 的相關(guān)授權(quán)信息,同時(shí)還有 P.J.Plauger 本人的版權(quán)信息。非開(kāi)源。
Rouge Wave STL
由 Rouge Wave 公司開(kāi)發(fā)的,也是繼承 HP STL 的一個(gè)版本,它也不是開(kāi)源的。
二、STL的基本組成
STL是由容器、算法、迭代器、函數(shù)對(duì)象、適配器、內(nèi)存分配器6部分構(gòu)成,其中迭代器、函數(shù)對(duì)象、適配器、內(nèi)存分配器是為容器、算法服務(wù)。
| 組成部分 | 含義 |
|---|---|
| 容器 | 一些封裝數(shù)據(jù)結(jié)構(gòu)的模板類(lèi) |
| 算法 | STL 提供了非常多(大約 100 個(gè))的數(shù)據(jù)結(jié)構(gòu)算法,它們都被設(shè)計(jì)成一個(gè)個(gè)的模板函數(shù),這些算法在 std 命名空間中定義,其中大部分算法都包含在頭文件 <algorithm> 中,少部分位于頭文件 <numeric> 中 |
| 迭代器 | 對(duì)容器中數(shù)據(jù)的讀和寫(xiě),是通過(guò)迭代器完成的,扮演著容器和算法之間的膠合劑 |
| 函數(shù)對(duì)象 | 一個(gè)類(lèi)將 () 運(yùn)算符重載為成員函數(shù),這個(gè)類(lèi)就稱(chēng)為函數(shù)對(duì)象類(lèi),這個(gè)類(lèi)的對(duì)象就是函數(shù)對(duì)象(又稱(chēng)仿函數(shù)) |
| 適配器 | 可以使一個(gè)類(lèi)的接口(模板的參數(shù))適配成用戶(hù)指定的形式,從而讓原本不能在一起工作的兩個(gè)類(lèi)工作在一起。值得一提的是,容器、迭代器和函數(shù)都有適配器 |
| 內(nèi)存分配器 | 為容器類(lèi)模板提供自定義的內(nèi)存申請(qǐng)和釋放功能 |
在 C++ 標(biāo)準(zhǔn)中,STL被重新組織為13個(gè)頭文件,如下:
| <iterator> | <functional> | <vector> | <deque> | <list> |
|---|---|---|---|---|
| <queue> | <stack> | <set> | <map> | <algorithm> |
| <numeric> | <memory> | <utility> |
注意:
或許是為了向下兼容,或許是為了內(nèi)部組織規(guī)劃,某些 STL 版本同時(shí)存儲(chǔ)具備擴(kuò)展名和無(wú)擴(kuò)展名的兩份文件,建議最好遵照C++規(guī)范,使用無(wú)擴(kuò)展名的頭文件。
三、容器是什么
在實(shí)際的開(kāi)發(fā)過(guò)程中,存取數(shù)據(jù)的方式會(huì)直接影響到對(duì)它們進(jìn)行增刪改查操作的復(fù)雜程度和時(shí)間消耗。
簡(jiǎn)單的理解容器,就是一些模板類(lèi)的集合,但和普通模板類(lèi)不同的是,容器中封裝的是組織數(shù)據(jù)的方法(也就是數(shù)據(jù)結(jié)構(gòu))。STL 提供有3類(lèi)標(biāo)準(zhǔn)容器,分別是序列容器、排序容器和哈希容器,其中后兩類(lèi)容器有時(shí)也統(tǒng)稱(chēng)為關(guān)聯(lián)容器,如下表:
| 容器種類(lèi) | 功能 |
|---|---|
| 序列容器 | 主要包括 vector 向量容器、list 列表容器以及 deque 雙端隊(duì)列容器。之所以被稱(chēng)為序列容器,是因?yàn)樵卦谌萜髦械奈恢猛氐闹禑o(wú)關(guān),即容器不是排序的。將元素插入容器時(shí),指定在什么位置,元素就會(huì)位于什么位置。 |
| 排序容器 | 包括 set 集合容器、multiset多重集合容器、map映射容器以及 multimap 多重映射容器。排序容器中的元素默認(rèn)是由小到大排序好的,即便是插入元素,元素也會(huì)插入到適當(dāng)位置。所以關(guān)聯(lián)容器在查找時(shí)具有非常好的性能。 |
| 哈希容器 | C++ 11 新加入 4 種關(guān)聯(lián)式容器,分別是 unordered_set 哈希集合、unordered_multiset 哈希多重集合、unordered_map 哈希映射以及 unordered_multimap 哈希多重映射。和排序容器不同,哈希容器中的元素是未排序的,元素的位置由哈希函數(shù)確定。 |
以上3類(lèi)容器的存儲(chǔ)方式完全不同,因此使用不同容器完成相同操作的效率也大不相同。因此在實(shí)際使用中,要根據(jù)具體的功能選擇最適合的容器。
四、迭代器
無(wú)論是序列容器還是關(guān)聯(lián)容器,最常做的操作無(wú)疑是遍歷容器中存儲(chǔ)的元素,而實(shí)現(xiàn)此操作,多數(shù)情況會(huì)選用“迭代器(iterator)”來(lái)實(shí)現(xiàn)。
雖然不同容器的內(nèi)部結(jié)構(gòu)各異,但它們本質(zhì)上都是用來(lái)存儲(chǔ)大量數(shù)據(jù)的,所以容器有一些操作方法是類(lèi)似的,因此完全可以利用泛型的技術(shù),將其設(shè)計(jì)成適用所有容器的通用算法,從未將容器和算法分離。
1、迭代器類(lèi)別
STL標(biāo)準(zhǔn)庫(kù)為每一種標(biāo)準(zhǔn)容器定義了一種迭代器類(lèi)型,即不同容器的迭代器不同,因此容器的迭代器功能的強(qiáng)弱也不同,進(jìn)而決定了容器是否哦支持STL中的某些算法。
常用的迭代器按功能強(qiáng)弱分為輸入迭代器、輸出迭代器、前向迭代器、雙向迭代器、隨機(jī)訪問(wèn)迭代器 5 種。輸入迭代器和輸出迭代器比較特殊,它們不是把數(shù)組或容器當(dāng)做操作對(duì)象,而是把輸入流/輸出流作為操作對(duì)象。關(guān)于輸入迭代器和輸出迭代器在這里暫時(shí)不多講。
假設(shè)存在一個(gè)迭代器Iter
1)前向迭代器(forward iterator)
Iter支持++Iter、Iter++、*Iter操作、被復(fù)制或賦值、可使用==和!=運(yùn)算符進(jìn)行比較
2)雙向迭代器(bidirectional iterator)
雙向迭代器具有正向迭代器的全部功能,除此之外,還可以進(jìn)行 --Iter 或者 Iter-- 操作(即一次向后移動(dòng)一個(gè)位置)。
3)隨機(jī)訪問(wèn)迭代器(random access iterator)
隨機(jī)訪問(wèn)迭代器具有雙向迭代器的全部功能。除此之外,假設(shè) i 是一個(gè)整型變量或常量,則 Iter 還支持以下操作:
| 操作 | 說(shuō)明 |
|---|---|
| Iter+=i | 使得 Iter 往后移動(dòng) i 個(gè)元素 |
| Iter-=i | 使得 Iter 往前移動(dòng) i 個(gè)元素 |
| Iter+i | 返回 Iter 后面第 i 個(gè)元素的迭代器 |
| Iter-i | 返回 Iter 前面第 i 個(gè)元素的迭代器 |
| Iter[i] | 返回 Iter 后面第 i 個(gè)元素的引用 |
兩個(gè)隨機(jī)訪問(wèn)迭代器 p1、p2 還可以用 <、>、<=、>= 運(yùn)算符進(jìn)行比較。另外,表達(dá)式 p2-p1 也是有定義的,其返回值表示 p2 所指向元素和 p1 所指向元素的序號(hào)之差。
五、容器對(duì)應(yīng)的迭代器
1、對(duì)應(yīng)關(guān)系
| 容器 | 迭代器類(lèi)別 |
|---|---|
| array | 隨機(jī)訪問(wèn)迭代器 |
| vector | 隨機(jī)訪問(wèn)迭代器 |
| deque | 隨機(jī)訪問(wèn)迭代器 |
| list | 雙向迭代器 |
| set / multiset | 雙向迭代器 |
| map / multimap | 雙向迭代器 |
| forward_list | 前向迭代器 |
| unordered_map / unordered_multimap | 前向迭代器 |
| unordered_set / unordered_multiset | 前向迭代器 |
| stack | 不支持迭代器 |
| queue | 不支持迭代器 |
注意:
容器適配器 stack 和 queue 沒(méi)有迭代器,它們包含有一些成員函數(shù),可以用來(lái)對(duì)元素進(jìn)行訪問(wèn)。
2、迭代器的定義方式
| 迭代器類(lèi)別 | 格式 |
|---|---|
| 正向迭代器 | 容器類(lèi)名::iterator 迭代器名; |
| 常量正向迭代器 | 容器類(lèi)名::const_iterator 迭代器名; |
| 反向迭代器 | 容器類(lèi)名::reverse_iterator 迭代器名; |
| 常量反向迭代器 | 容器類(lèi)名::const_reverse_iterator 迭代器名; |
說(shuō)明:
*迭代器名:迭代器指向的元素
常量迭代器和非常量迭代器的分別在于:通過(guò)非常量迭代器還能修改其指向的元素
反向迭代器和正向迭代器的區(qū)別在于:對(duì)正向迭代器進(jìn)行 ++ 操作時(shí),迭代器會(huì)指向容器中的后一個(gè)元素;而對(duì)反向迭代器進(jìn)行 ++ 操作時(shí),迭代器會(huì)指向容器中的前一個(gè)元素。
以上 4 種定義迭代器的方式,并不是每個(gè)容器都適用。
六、總結(jié)




