一、STL簡(jiǎn)介
STL(Standard Template Library,標(biāo)準(zhǔn)模板庫(kù))是惠普實(shí)驗(yàn)室開(kāi)發(fā)的一系列軟件的統(tǒng)稱。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普實(shí)驗(yàn)室工作時(shí)所開(kāi)發(fā)出來(lái)的。現(xiàn)在雖說(shuō)它主要出現(xiàn)在C++中,但在被引入C++之前該技術(shù)就已經(jīng)存在了很長(zhǎng)的一段時(shí)間。
STL的代碼從廣義上講分為三類:algorithm(算法)、container(容器)和iterator(迭代器),幾乎所有的代碼都采用了模板類和模版函數(shù)的方式,這相比于傳統(tǒng)的由函數(shù)和類組成的庫(kù)來(lái)說(shuō)提供了更好的代碼重用機(jī)會(huì)。在C++標(biāo)準(zhǔn)中,STL被組織為下面的13個(gè)頭文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、<memory>、<numeric>、<queue>、<set>、<stack>和<utility>。以下筆者就簡(jiǎn)單介紹一下STL各個(gè)部分的主要特點(diǎn)。
二、算法
大家都能取得的一個(gè)共識(shí)是函數(shù)庫(kù)對(duì)數(shù)據(jù)類型的選擇對(duì)其可重用性起著至關(guān)重要的作用。舉例來(lái)說(shuō),一個(gè)求方根的函數(shù),在使用浮點(diǎn)數(shù)作為其參數(shù)類型的情況下的可重用性肯定比使用整型作為它的參數(shù)類性要高。而C++通過(guò)模板的機(jī)制允許推遲對(duì)某些類型的選擇,直到真正想使用模板或者說(shuō)對(duì)模板進(jìn)行特化的時(shí)候,STL就利用了這一點(diǎn)提供了相當(dāng)多的有用算法。它是在一個(gè)有效的框架中完成這些算法的——你可以將所有的類型劃分為少數(shù)的幾類,然后就可以在模版的參數(shù)中使用一種類型替換掉同一種類中的其他類型。
STL提供了大約100個(gè)實(shí)現(xiàn)算法的模版函數(shù),比如算法for_each將為指定序列中的每一個(gè)元素調(diào)用指定的函數(shù),stable_sort以你所指定的規(guī)則對(duì)序列進(jìn)行穩(wěn)定性排序等等。這樣一來(lái),只要我們熟悉了STL之后,許多代碼可以被大大的化簡(jiǎn),只需要通過(guò)調(diào)用一兩個(gè)算法模板,就可以完成所需要的功能并大大地提升效率。
算法部分主要由頭文件<algorithm>,<numeric>和<functional>組成。<algorithm>是所有STL頭文件中最大的一個(gè)(盡管它很好理解),它是由一大堆模版函數(shù)組成的,可以認(rèn)為每個(gè)函數(shù)在很大程度上都是獨(dú)立的,其中常用到的功能范圍涉及到比較、交換、查找、遍歷操作、復(fù)制、修改、移除、反轉(zhuǎn)、排序、合并等等。<numeric>體積很小,只包括幾個(gè)在序列上面進(jìn)行簡(jiǎn)單數(shù)學(xué)運(yùn)算的模板函數(shù),包括加法和乘法在序列上的一些操作。<functional>中則定義了一些模板類,用以聲明函數(shù)對(duì)象。
三、容器
在實(shí)際的開(kāi)發(fā)過(guò)程中,數(shù)據(jù)結(jié)構(gòu)本身的重要性不會(huì)遜于操作于數(shù)據(jù)結(jié)構(gòu)的算法的重要性,當(dāng)程序中存在著對(duì)時(shí)間要求很高的部分時(shí),數(shù)據(jù)結(jié)構(gòu)的選擇就顯得更加重要。
經(jīng)典的數(shù)據(jù)結(jié)構(gòu)數(shù)量有限,但是我們常常重復(fù)著一些為了實(shí)現(xiàn)向量、鏈表等結(jié)構(gòu)而編寫(xiě)的代碼,這些代碼都十分相似,只是為了適應(yīng)不同數(shù)據(jù)的變化而在細(xì)節(jié)上有所出入。STL容器就為我們提供了這樣的方便,它允許我們重復(fù)利用已有的實(shí)現(xiàn)構(gòu)造自己的特定類型下的數(shù)據(jù)結(jié)構(gòu),通過(guò)設(shè)置一些模版類,STL容器對(duì)最常用的數(shù)據(jù)結(jié)構(gòu)提供了支持,這些模板的參數(shù)允許我們指定容器中元素的數(shù)據(jù)類型,可以將我們?cè)S多重復(fù)而乏味的工作簡(jiǎn)化。
容器部分主要由頭文件<vector>,<list>,<deque>,<set>,<map>,<stack>和<queue>組成。對(duì)于常用的一些容器和容器適配器(可以看作由其它容器實(shí)現(xiàn)的容器),可以通過(guò)下表總結(jié)一下它們和相應(yīng)頭文件的對(duì)應(yīng)關(guān)系。
數(shù)據(jù)結(jié)構(gòu)
|
描述
|
實(shí)現(xiàn)頭文件
|
向量(vector) |
連續(xù)存儲(chǔ)的元素 |
<vector> |
列表(list) |
由節(jié)點(diǎn)組成的雙向鏈表,每個(gè)結(jié)點(diǎn)包含著一個(gè)元素 |
<list> |
雙隊(duì)列(deque) |
連續(xù)存儲(chǔ)的指向不同元素的指針?biāo)M成的數(shù)組 |
<deque> |
集合(set) |
由節(jié)點(diǎn)組成的紅黑樹(shù),每個(gè)節(jié)點(diǎn)都包含著一個(gè)元素,節(jié)點(diǎn)之間以某種作用于元素對(duì)的謂詞排列,沒(méi)有兩個(gè)不同的元素能夠擁有相同的次序 |
<set> |
多重集合(multiset) |
允許存在兩個(gè)次序相等的元素的集合 |
<set> |
棧(stack) |
后進(jìn)先出的值的排列 |
<stack> |
隊(duì)列(queue) |
先進(jìn)先出的執(zhí)的排列 |
<queue> |
優(yōu)先隊(duì)列(priority_queue) |
元素的次序是由作用于所存儲(chǔ)的值對(duì)上的某種謂詞決定的的一種隊(duì)列 |
<queue> |
映射(map) |
由{鍵,值}對(duì)組成的集合,以某種作用于鍵對(duì)上的謂詞排列 |
<map> |
多重映射(multimap) |
允許鍵對(duì)有相等的次序的映射 |
<map> |
四、迭代器
下面要說(shuō)的迭代器從作用上來(lái)說(shuō)是最基本的部分,可是理解起來(lái)比前兩者都要費(fèi)力一些(至少筆者是這樣)。軟件設(shè)計(jì)有一個(gè)基本原則,所有的問(wèn)題都可以通過(guò)引進(jìn)一個(gè)間接層來(lái)簡(jiǎn)化,這種簡(jiǎn)化在STL中就是用迭代器來(lái)完成的。概括來(lái)說(shuō),迭代器在STL中用來(lái)將算法和容器聯(lián)系起來(lái),起著一種黏和劑的作用。幾乎STL提供的所有算法都是通過(guò)迭代器存取元素序列進(jìn)行工作的,每一個(gè)容器都定義了其本身所專有的迭代器,用以存取容器中的元素。
迭代器部分主要由頭文件<utility>,<iterator>和<memory>組成。<utility>是一個(gè)很小的頭文件,它包括了貫穿使用在STL中的幾個(gè)模板的聲明,<iterator>中提供了迭代器使用的許多方法,而對(duì)于<memory>的描述則十分的困難,它以不同尋常的方式為容器中的元素分配存儲(chǔ)空間,同時(shí)也為某些算法執(zhí)行期間產(chǎn)生的臨時(shí)對(duì)象提供機(jī)制,<memory>中的主要部分是模板類allocator,它負(fù)責(zé)產(chǎn)生所有容器中的默認(rèn)分配器。
五、對(duì)初學(xué)者學(xué)習(xí)STL的一點(diǎn)建議
對(duì)于之前不太了解STL的讀者來(lái)說(shuō),上面的文字只是十分概括地描述了一下STL的框架,對(duì)您理解STL的機(jī)制乃至使用STL所起到的幫助微乎甚微,這不光是因?yàn)樯钊隨TL需要對(duì)C++的高級(jí)應(yīng)用有比較全面的了解,更因?yàn)镾TL的三個(gè)部分算法、容器和迭代器三部分是互相牽制或者說(shuō)是緊密結(jié)合的。從概念上講最基礎(chǔ)的部分是迭代器,可是直接學(xué)習(xí)迭代器會(huì)遇到許多抽象枯燥和繁瑣的細(xì)節(jié),然而不真正理解迭代器又是無(wú)法直接進(jìn)入另兩部分的學(xué)習(xí)的(至少對(duì)剖析源碼來(lái)說(shuō)是這樣)。可以說(shuō),適應(yīng)STL處理問(wèn)題的方法是需要花費(fèi)一定的時(shí)間的,但是以此為代價(jià),STL取得了一種十分可貴的獨(dú)立性,它通過(guò)迭代器能在盡可能少地知道某種數(shù)據(jù)結(jié)構(gòu)的情況下完成對(duì)這一結(jié)構(gòu)的運(yùn)算,所以下決心鉆研STL的朋友們千萬(wàn)不要被一時(shí)的困難擊倒。其實(shí)STL運(yùn)用的模式相對(duì)統(tǒng)一,只要適應(yīng)了它,從一個(gè)STL工具到另一個(gè)工具,都不會(huì)有什么大的變化。
對(duì)于STL的使用,也普遍存在著兩種觀點(diǎn)。第一種認(rèn)為STL的最大作用在于充當(dāng)經(jīng)典的數(shù)據(jù)結(jié)構(gòu)和算法教材,因?yàn)樗脑创a涉及了許多具體實(shí)現(xiàn)方面的問(wèn)題。第二種則認(rèn)為STL的初衷乃是為了簡(jiǎn)化設(shè)計(jì),避免重復(fù)勞動(dòng),提高編程效率,因此應(yīng)該是“應(yīng)用至上”的,對(duì)于源代碼則不必深究。筆者則認(rèn)為分析源代碼和應(yīng)用并不矛盾,通過(guò)分析源代碼也能提高我們對(duì)其應(yīng)用的理解,當(dāng)然根據(jù)具體的目的也可以有不同的側(cè)重。
最后要說(shuō)的是,STL是ANSI/ISO C++標(biāo)準(zhǔn)的一部分,所以對(duì)于一個(gè)可以有多種C++實(shí)現(xiàn)的過(guò)程,首先考慮的應(yīng)該是STL提供的模板(高效且可移植性好),其次才是各個(gè)廠商各自相應(yīng)的庫(kù)(高效但可移植性不好)以及自己去編寫(xiě)代碼(可移植性好但低效)。
|