STL(Standard Template Library)里有很多組成部分,但是主要有三個,容器爱榔、迭代器和算法
容器用來管理某個特定對象的集合掉冶。每一種容器都有自己的優(yōu)點和缺點真竖,在項目中根據(jù)不同的需求,使用不同的容器厌小。容器可以是數(shù)組恢共、鏈表或者類字典。
迭代器用于遍歷對象集合的元素璧亚。這些集合可以是容器或容器的子集讨韭。每一個容器類都提供了它自己的迭代器類型。
算法用來處理的元素的集合癣蟋。例如透硝,可以進行搜索、排序等操作疯搅。
STL的數(shù)據(jù)和操作是分離的濒生。數(shù)據(jù)存儲在容器里,使用算法進行操作幔欧。迭代器是這兩者之間的粘合劑罪治,讓算法與容器可以進行交互。
某種程度上礁蔗,STL的概念與面向?qū)ο缶幊痰脑瓌t相背觉义,
STL數(shù)據(jù)和算法是分離的而不是結(jié)合。STL是泛型編程的一個很好的例子浴井。容器和算法分別是任意類型和類的泛型晒骇。STL提供了更通用的組件。還可以通過使用適配器和仿函數(shù)來達到特殊要求。
容器
容器管理著一系列元素厉碟,為了滿足不同的需求喊巍,STL提供了多種類型的容器,見下圖箍鼓。
主要可以分為三大類
序列容器是有序集合崭参,其中的每個元素都有特定位置。這個位置取決于插入的時間和地點款咖,但是它跟元素的值無關(guān)何暮。STL包含5個預(yù)定義的序列容器類:array、vector铐殃、deque海洼、list和forward_list。
關(guān)聯(lián)容器是把元素的值按照某種規(guī)則排好順序的集合富腊。STL包含4個預(yù)定義的關(guān)聯(lián)容器類:set坏逢、multiset、map和multimap赘被。
無序(關(guān)聯(lián))容器是無序集合是整。主要關(guān)注一個元素是否在集合中。不論是插入的順序還是插入元素的值對元素的位置都沒有任何影響民假。STL包含4個預(yù)定義的無序容器類:unordered_set浮入、unordered_multiset、unordered_map和unordered_multimap羊异。
序列容器通常是數(shù)組或鏈表的實現(xiàn)
關(guān)聯(lián)容器通常是二叉樹的實現(xiàn)
無序容器通常是哈希表的實現(xiàn)
容器適配器
容器適配器提供順序容器的特殊接口
stack 堆棧適配器(LIFO)
queue 改寫容器來提供隊列(FIFO數(shù)據(jù)結(jié)構(gòu))
priority_queue 改寫容器來提供優(yōu)先級隊列
迭代器
根據(jù)迭代器所支持的操作事秀,一般分為下面5種。
前向迭代器只能利用遞增運算符進行前向迭代野舶。像unordered_set易迹、unordered_multiset、unordered_map和unordered_multimap這些容器都“至少”是用前向迭代器(某些情況下可以提供雙向迭代器)筒愚。
雙向迭代器是可以用遞增運算符向前迭代赴蝇,或者用遞減運算符向后迭代菩浙。像list巢掺、set、multiset劲蜻、map和multimap的迭代器都是雙向迭代器陆淀。
隨機訪問迭代器具有雙向迭代器的所有屬性。此外先嬉,他們還可以進行隨機訪問轧苫。這種迭代器本身支持運算操作,可以改變偏移量,也可以利用關(guān)系運算符(< 和 >)比較迭代器含懊。像vector身冬、deque、array和string的迭代器都是這類迭代器岔乔。
輸入迭代器能夠在迭代時讀取或處理一些值酥筝。如Input stream iterators。
輸出迭代器能夠在迭代時輸出一些值雏门。如Inserters嘿歌、和output stream iterators。
算法
STL提供了一些標準算法來處理集合元素茁影。這些算法一般提供最基本的功能宙帝,如搜索、排序募闲、復(fù)制步脓、修改和數(shù)值處理。
算法不是容器類的成員函數(shù)浩螺,而是全局函數(shù)沪编。算法可以操作不同容器類型的元素,甚至可以操作用戶自定義的容器類型年扩∫侠總之,既減少了代碼量厨幻,又增強了性能相嵌。
迭代器適配器
任何操作起來像迭代器的東西都可以當作迭代器。所以可以寫出像迭代器的一些類但又執(zhí)行不一樣的操作况脆。C++標準庫提供的一些預(yù)定義的特殊迭代器饭宾,即迭代器適配器。
一般分為四類:
Insert iterators也稱為inserters格了,用來將“賦值新值”操作轉(zhuǎn)換為“安插新值”操作看铆。通過這種迭代器,算法可以執(zhí)行安插(insert)行為而非覆蓋(overwrite)行為盛末。所有Insert迭代器都隸屬于Output迭代器類型弹惦,所以它只提供賦值(assign)新值的能力。通常算法會將數(shù)值賦值給目的迭代器悄但,如copy()算法
Stream iterators是一種迭代器配接器棠隐,可以把stream當成算法的原點和終點。更明確的說檐嚣,一個istream迭代器可以用來從input stream中讀元素助泽,而一個ostream迭代器可以用來對output stream寫入元素。Stream迭代器的一種特殊形式是所謂的stream緩沖區(qū)迭代器,用來對stream緩沖區(qū)進行直接讀取和寫入操作嗡贺。
Reverse iterators重新定義遞增運算和遞減運算隐解,使其行為正好倒置。
Move iterators很像一個底層迭代器(必須至少有一個InputIterator)诫睬。如果這個迭代器被當作輸入迭代器來用厢漩,要注意的是,值的操作是移動而不是復(fù)制岩臣。
重點介紹向量:
向量容器使用動態(tài)數(shù)組存儲溜嗜、管理對象。因為數(shù)組是一個隨機訪問數(shù)據(jù)結(jié)構(gòu)架谎,所以可以隨機訪問向量中的元素炸宵。在數(shù)組中間或是開始處插入一個元素是費時的,特別是在數(shù)組非常大的時候更是如此谷扣。然而在數(shù)組末端插入元素卻很快土全。
實現(xiàn)向量容器的類名是vector(容器是類模板)。包含vector類的頭文件名是vector会涎。所以裹匙,如果要在程序里使用向量容器,就要在程序中包含下面語句:
#include
此外末秃,在定義向量類型對象時概页,必須指定該對象的類型,因為vector類是一個類模板练慕。例如惰匙,語句:
vector intList;
將intList聲明為一個元素類型為int的向量容器對象。類似地铃将,語句:
vector stringList;將stringList聲明為一個元素類型為string的向量容器對象项鬼。
聲明向量對象
vector類包含了多個構(gòu)造函數(shù),其中包括默認構(gòu)造函數(shù)劲阎。因此绘盟,可以通過多種方式來聲明和初始化向量容器。表一描述了怎樣聲明和初始化指定類型的向量容器悯仙。
表一???? 各種聲明和初始向量容器的方法
語句作用
vector vecList;創(chuàng)建一個沒有任何元素的空向量vecList(使用默認構(gòu)造函數(shù))
vector vecList(otherVecList)創(chuàng)建一個向量vecList龄毡,并使用向量otherVecList中的元素初始化該向量。向量vecList與向量otherVecList的類型相同
vector vecLIst(size);
創(chuàng)建一個大小為size的向量vecList雁比,并使用默認構(gòu)造函數(shù)初始化該向量
vector vecList(n,elem);創(chuàng)建一個大小為n的向量vecList稚虎,該向量中所有的n個元素都初始化為elem
vector vecList(begin,end);創(chuàng)建一個向量vecList,并初始化該向量(begin,end)中的元素偎捎。即,從begin到end-1之間的所有元素
在介紹了如何聲明向量順序容器之后,讓我們開始討論如何操作向量容器中的數(shù)據(jù)茴她。首先寻拂,必須要知道下面幾種基本操作:
元素插入
元素刪除
遍歷向量容器中的元素
假設(shè)vecList是一個向量類型容器。表二給出了在vecList中插入元素和刪除元素的操作丈牢,這些操作是vector類的成員函數(shù)祭钉。表二還說明了如何使用這些操作。
表二???? 向量容器上的各種操作
語句作用
vecList.clear()從容器中刪除所有元素
vecList.erase(position)刪除由position指定的位置上的元素
vecList.erase(beg,end)刪除從beg到end-1之間的所有元素
vecList.insert(position, elem)將elem的一個拷貝插入到由position指定的位置上己沛,并返回新元素的位置
vecList.inser(position, n, elem)將elem的n個拷貝插入到由 position指定的位置上
vecList.insert(position, beg, end)將從beg到end-1之間的所有元素的拷貝插入到vecList中由position指定的位置上
vecList.push_back(elem)將elem的一個拷貝插入致List的末尾
vecList.pop_back()刪除最后元素
vecList.resize(num)將元素個數(shù)改為num慌核。如果size()增加,默認的構(gòu)造函數(shù)負責創(chuàng)建這些新元素
vecList.resize(num, elem)將元素個數(shù)改為num申尼。如果size()增加垮卓,默認的構(gòu)造函數(shù)將這些新元素初始化為elem
在向量容器中聲明迭代器
vector類包含了一個typedef iterator,這是一個public成員师幕。通過iterator粟按,可以聲明向量容器中的迭代器。例如霹粥,語句:
vector::iterator intVeciter;??????? 將intVecIter聲明為int類型的向量容器迭代器灭将。
因為iterator是一個定義在vector類中的typedef,所以必須使用容器名(vector)后控、容器元素類型和作用域符來使用iterator庙曙。
表達式:
++intVecIter
將迭代器intVecIter加1,使其指向容器中的下一個元素浩淘。表達式:*intVecIter
返回當前迭代器位置上的元素矾利。
注意,迭代器上的這些操作和指針上的相應(yīng)操作是相同的馋袜。運算符*作為單目運算符使用時男旗,稱為遞引用運算符。
下面將討論如何使用迭代器來操作向量容器中的數(shù)據(jù)。假設(shè)有下面語句:
vector intList;
vector::iterator intVecIter;
第一行中的語句將intList聲明為元素為int類型的向量容器。第二行中的語句將intVecIter聲明為元素為int類型的向量容器的迭代器涛酗。
容器與函數(shù)begin和end
所有容器都包含成員函數(shù)begin和end再层。函數(shù)begin返回容器中第一個元素的位置;函數(shù)end返回容器中最后一個元素的位置蠕嫁。這兩個函數(shù)都沒有參數(shù)。在執(zhí)行下面語句:
intVecIter = intList.begin();
迭代器intVecIter指向容器intList中第一個元素。
下面的for循環(huán)將intList中所有元素輸出互標準輸出設(shè)備上:
for (intVecIter = intList.begin(); intVecIter != intList.end();
cout<<*intVecList<<"???? ";
可以通過表三中給出的操作直接訪問向量容器中的元素稻爬。
表三 訪問向量容器中元素的操作
表達式作用
vecList.at(index)返回由index指定的位置上的元素
vecList[index]返回由index指定的位置上的元素
vecList.front()返回第一個元素 (不檢查容器是否為空)
vecList.back()返回最后一個元素(不檢查容器是否為空)
表三說明:可以按照數(shù)組的方式來處理向量中的元素(注意蜕依,在C++中桅锄,數(shù)組下標從0始琉雳。,向量容器中第一個元素的位置也是0)友瘤。
徽號類中還包含:返回容器中當前元素個數(shù)的成員函數(shù)翠肘,返回可以插入到容器中的元素的最大個數(shù)的成員函數(shù)等。表四描述其中 一些操作(假設(shè)vecCont是向量容器)辫秧。
表四 計算向量容器大小的操作
表達式作用
vecCont.capacity()返回不重新分配空間可以插入到容器vecCont中的元素的最大個數(shù)
vecCont.empty()容器vecCont為空束倍,返回true;否則盟戏,返回false
vecCont.size()返回容器vecCont中當前的個數(shù)
vecCont.max_size()返回可以插入到容器vecCont中的元素的最大個數(shù)