c++復習:STL之理論基礎
1 STL(標準模板庫)理論基礎
1.1基本概念
STL(Standard Template Library,標準模板庫)是惠普實驗室開發的一系列軟件的統稱。現然主要出現在C++中,但在被引入C++之前該技術就已經存在了很長的一段時間。
STL的從廣義上講分為三類:algorithm(算法)、container(容器)和iterator(叠代器),容器和算法通過叠代器可以進行無縫地連接。幾乎所有的代碼都采 用了模板類和模板函數的方式,這相比於傳統的由函數和類組成的庫來說提供了更好的代碼重用機會。在C++標準中,STL被組織為下面的13個頭文 件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、<memory>、<numeric>、<queue>、<set>、<stack> 和<utility>。
STL詳細的說六大組件
- 容器(Container)
- 算法(Algorithm)
- 叠代器(Iterator)
- 仿函數(Function object)
- 適配器(Adaptor)
- 空間配制器(allocator)
使用STL的好處
1)STL是C++的一部分,因此不用額外安裝什麽,它被內建在你的編譯器之內。
2)STL的一個重要特點是數據結構和算法的分離。盡管這是個簡單的概念,但是這種分離確實使得STL變得非常通用。
例如,在STL的vector容器中,可以放入元素、基礎數據類型變量、元素的地址;
STL的sort()函數可以用來操作vector,list等容器。
- 程序員可以不用思考STL具體的實現過程,只要能夠熟練使用STL就OK了。這樣他們就可以把精力放在程序開發的別的方面。
- STL具有高可重用性,高性能,高移植性,跨平臺的優點。
高可重用性:STL中幾乎所有的代碼都采用了模板類和模版函數的方式實現,這相比於傳統的由函數和類組成的庫來說提供了更好的代碼重用機會。關於模板的知識,已經給大家介紹了。
高性能:如map可以高效地從十萬條記錄裏面查找出指定的記錄,因為map是采用紅黑樹的變體實現的。(紅黑樹是平橫二叉樹的一種)
高移植性:如在項目A上用STL編寫的模塊,可以直接移植到項目B上。
跨平臺:如用windows的Visual Studio編寫的代碼可以在Mac OS的XCode上直接編譯。
- 程序員可以不用思考STL具體的實現過程,只要能夠熟練使用STL就OK了。這樣他們就可以把精力放在程序開發的別的方面。
- 了解到STL的這些好處,我們知道STL無疑是最值得C++程序員驕傲的一部分。每一個C++程序員都應該好好學習STL。只有能夠熟練使用STL的程序員,才是好的C++程序員。
- 總之:招聘工作中,經常遇到C++程序員對STL不是非常了解。大多是有一個大致的映像,而對於在什麽情況下應該使用哪個容器和算法都感到比較茫然。STL是C++程序員的一項不可或缺的基本技能,掌握它對提升C++編程大有裨益。
1.2 容器
在實際的開發過程中,數據結構本身的重要性不會遜於操作於數據結構的算法的重要性,當程序中存在著對時間要求很高的部分時,數據結構的選擇就顯得更加重要。
經典的數據結構數量有限,但是我們常常重復著一些為了實現向量、鏈表等結構而編寫的代碼,這些代碼都十分相似,只是為了適應不同數據的變化而在 細節上有所出入。STL容器就為我們提供了這樣的方便,它允許我們重復利用已有的實現構造自己的特定類型下的數據結構,通過設置一些模板,STL容器對最常用的數據結構提供了支持,這些模板的參數允許我們指定容器中元素的數據類型,可以將我們許多重復而乏味的工作簡化。
容器部分主要由頭文 件<vector>,<list>,<deque>,<set>,<map>,<stack> 和<queue>組成。對於常用的一些容器和容器適配器(可以看作由其它容器實現的容器),可以通過下表總結一下它們和相應頭文件的對應關系。
1.2.1容器的概念
用來管理一組元素
1.2.2容器的分類
序列式容器(Sequence containers)
每個元素都有固定位置--取決於插入時機和地點,和元素值無關。
vector、deque、list
關聯式容器(Associated containers)
元素位置取決於特定的排序準則,和插入順序無關
set、multiset、map、multimap
數據結構 | 描述 | 實現頭文件 |
向量(vector) | 連續存儲的元素 | <vector> |
列表(list) | 由節點組成的雙向鏈表,每個結點包含著一個元素 | <list> |
雙隊列(deque) | 連續存儲的指向不同元素的指針所組成的數組 | <deque> |
集合(set) | 由節點組成的紅黑樹,每個節點都包含著一個元素,節點之間以某種作用於元素對的謂詞排列,沒有兩個不同的元素能夠擁有相同的次序 | <set> |
多重集合(multiset) | 允許存在兩個次序相等的元素的集合 | <set> |
棧(stack) | 後進先出的值的排列 | <stack> |
隊列(queue) | 先進先出的執的排列 | <queue> |
優先隊列(priority_queue) | 元素的次序是由作用於所存儲的值對上的某種謂詞決定的的一種隊列 | <queue> |
映射(map) | 由{鍵,值}對組成的集合,以某種作用於鍵對上的謂詞排列 | <map> |
多重映射(multimap) | 允許鍵對有相等的次序的映射 | <map> |
1.3叠代器
叠代器從作用上來說是最基本的部分,可是理解起來比前兩者都要費力一些。軟件設計有一個基本原則,所有的問題都可以通過引進一個間接層來簡化, 這種簡化在STL中就是用叠代器來完成的。概括來說,叠代器在STL中用來將算法和容器聯系起來,起著一種黏和劑的作用。幾乎STL提供的所有算法都是通 過叠代器存取元素序列進行工作的,每一個容器都定義了其本身所專有的叠代器,用以存取容器中的元素。
叠代器部分主要由頭文件<utility>,<iterator>和<memory>組 成。<utility>是一個很小的頭文件,它包括了貫穿使用在STL中的幾個模板的聲明,<iterator>中提供了叠代器 使用的許多方法,而對於<memory>的描述則十分的困難,它以不同尋常的方式為容器中的元素分配存儲空間,同時也為某些算法執行期間產生 的臨時對象提供機制,<memory>中的主要部分是模板類allocator,它負責產生所有容器中的默認分配器。
1.4算法
函數庫對數據類型的選擇對其可重用性起著至關重要的作用。舉例來說,一個求方根的函數,在使用浮點數作為其參數類型的情況下的可重用性肯定比使 用整型作為它的參數類性要高。而C++通過模板的機制允許推遲對某些類型的選擇,直到真正想使用模板或者說對模板進行特化的時候,STL就利用了這一點提 供了相當多的有用算法。它是在一個有效的框架中完成這些算法的——可以將所有的類型劃分為少數的幾類,然後就可以在模版的參數中使用一種類型替換掉同一種 類中的其他類型。
STL提供了大約100個實現算法的模版函數,比如算法for_each將為指定序列中的每一個元素調用指定的函數,stable_sort以 你所指定的規則對序列進行穩定性排序等等。這樣一來,只要熟悉了STL之後,許多代碼可以被大大的化簡,只需要通過調用一兩個算法模板,就可以完成所需要 的功能並大大地提升效率。
算法部分主要由頭文件<algorithm>,<numeric>和<functional>組 成。<algorithm>是所有STL頭文件中最大的一個(盡管它很好理解),它是由一大堆模版函數組成的,可以認為每個函數在很大程度上 都是獨立的,其中常用到的功能範圍涉及到比較、交換、查找、遍歷操作、復制、修改、移除、反轉、排序、合並等等。<numeric>體積很 小,只包括幾個在序列上面進行簡單數學運算的模板函數,包括加法和乘法在序列上的一些操作。<functional>中則定義了一些模板類, 用以聲明函數對象。
1.5 C++標準庫
C++強大的功能來源於其豐富的類庫及庫函數資源。C++標準庫的內容總共在50個標準頭文件中定義。在C++開發中,要盡可能地利用標準庫完 成。這樣做的直接好處包括:
(1)成本:已經作為標準提供,何苦再花費時間、人力重新開發呢;
(2)質量:標準庫的都是經過嚴格測試的,正確性有保證;
(3)效率:關於人的效率已經體現在成本中了,關於代碼的執行效率要相信實現標準庫的大牛們的水平;
(4)良好的編程風格:采用行業中普遍的做法進行開發。
在C++程序設計課程中,尤其是作為第一門程序設計課程,我們註重了語法、語言的機制等方面的內容。程序設計能力的培養有個過程,跨過基本的原 理性知識直接進入到工程中的普遍做法,由於跨度決定了其難度。再者,在掌握了基本原理的基礎上,在認識標準庫的問題上完全可以憑借實踐,逐步地掌握。標準庫的學習不需要認認真真地讀書,需要的是在了解概貌的情況下,在實踐中深入。
C++標準庫的內容分為10類,分別是(建議在閱讀中,將你已經用過或聽說過的頭文件劃出來):
C1. 標準庫中與語言支持功能相關的頭文件
頭文件 | 描 述 |
<cstddef> | 定義宏NULL和offsetof,以及其他標準類型size_t和ptrdiff_t。與對應的標準C頭文件的區別是,NULL是C++空指針常量的補充定義,宏offsetof接受結構或者聯合類型參數,只要他們沒有成員指針類型的非靜態成員即可。 |
<limits> | 提供與基本數據類型相關的定義。例如,對於每個數值數據類型,它定義了可以表示出來的最大值和最小值以及二進制數字的位數。 |
<climits> | 提供與基本整數數據類型相關的C樣式定義。這些信息的C++樣式定義在<limits>中 |
<cfloat> | 提供與基本浮點型數據類型相關的C樣式定義。這些信息的C++樣式定義在<limits>中 |
<cstdlib> | 提供支持程序啟動和終止的宏和函數。這個頭文件還聲明了許多其他雜項函數,例如搜索和排序函數,從字符串轉換為數值等函數。它與對應的標準C頭文件 stdlib.h不同,定義了abort(void)。abort()函數還有額外的功能,它不為靜態或自動對象調用析構函數,也不調用傳給 atexit()函數的函數。它還定義了exit()函數的額外功能,可以釋放靜態對象,以註冊的逆序調用用atexit()註冊的函數。清除並關閉所有 打開的C流,把控制權返回給主機環境。 |
<new> | 支持動態內存分配 |
<typeinfo> | 支持變量在運行期間的類型標識 |
<exception> | 支持異常處理,這是處理程序中可能發生的錯誤的一種方式 |
<cstdarg> | 支持接受數量可變的參數的函數。即在調用函數時,可以給函數傳送數量不等的數據項。它定義了宏va_arg、va_end、va_start以及va_list類型 |
<csetjmp> | 為C樣式的非本地跳躍提供函數。這些函數在C++中不常用 |
<csignal> | 為中斷處理提供C樣式支持 |
C2. 支持流輸入/輸出的頭文件
頭文件 | 描 述 |
<iostream> | 支持標準流cin、cout、cerr和clog的輸入和輸出,它還支持多字節字符標準流wcin、wcout、wcerr和wclog。 |
<iomanip> | 提供操縱程序,允許改變流的狀態,從而改變輸出的格式。 |
<ios> | 定義iostream的基類 |
<istream> | 為管理輸出流緩存區的輸入定義模板類 |
<ostream> | 為管理輸出流緩存區的輸出定義模板類 |
<sstream> | 支持字符串的流輸入輸出 |
<fstream> | 支持文件的流輸入輸出 |
<iosfwd> | 為輸入輸出對象提供向前的聲明 |
<streambuf> | 支持流輸入和輸出的緩存 |
<cstdio> | 為標準流提供C樣式的輸入和輸出 |
<cwchar> | 支持多字節字符的C樣式輸入輸出 |
C3. 與診斷功能相關的頭文件
頭文件 | 描 述 |
<stdexcept> | 定義標準異常。異常是處理錯誤的方式 |
<cassert> | 定義斷言宏,用於檢查運行期間的情形 |
<cerrno> | 支持C樣式的錯誤信息 |
C4. 定義工具函數的頭文件
頭文件 | 描 述 |
<utility> | 定義重載的關系運算符,簡化關系運算符的寫入,它還定義了pair類型,該類型是一種模板類型,可以存儲一對值。這些功能在庫的其他地方使用 |
<functional> | 定義了許多函數對象類型和支持函數對象的功能,函數對象是支持operator()()函數調用運算符的任意對象 |
<memory> | 給容器、管理內存的函數和auto_ptr模板類定義標準內存分配器 |
<ctime> | 支持系統時鐘函數 |
C5. 支持字符串處理的頭文件
頭文件 | 描 述 |
<string> | 為字符串類型提供支持和定義,包括單字節字符串(由char組成)的string和多字節字符串(由wchar_t組成) |
<cctype> | 單字節字符類別 |
<cwctype> | 多字節字符類別 |
<cstring> | 為處理非空字節序列和內存塊提供函數。這不同於對應的標準C庫頭文件,幾個C樣式字符串的一般C庫函數被返回值為const和非const的函數對替代了 |
<cwchar> | 為處理、執行I/O和轉換多字節字符序列提供函數,這不同於對應的標準C庫頭文件,幾個多字節C樣式字符串操作的一般C庫函數被返回值為const和非const的函數對替代了。 |
<cstdlib> | 為把單字節字符串轉換為數值、在多字節字符和多字節字符串之間轉換提供函數 |
C6. 定義容器類的模板的頭文件
<vector> | 定義vector序列模板,這是一個大小可以重新設置的數組類型,比普通數組更安全、更靈活 |
<list> | 定義list序列模板,這是一個序列的鏈表,常常在任意位置插入和刪除元素 |
<deque> | 定義deque序列模板,支持在開始和結尾的高效插入和刪除操作 |
<queue> | 為隊列(先進先出)數據結構定義序列適配器queue和priority_queue |
<stack> | 為堆棧(後進先出)數據結構定義序列適配器stack |
<map> | map是一個關聯容器類型,允許根據鍵值是唯一的,且按照升序存儲。multimap類似於map,但鍵不是唯一的。 |
<set> | set是一個關聯容器類型,用於以升序方式存儲唯一值。multiset類似於set,但是值不必是唯一的。 |
<bitset> | 為固定長度的位序列定義bitset模板,它可以看作固定長度的緊湊型bool數組 |
C7. 支持叠代器的頭文件
頭文件 | 描述 |
<iterator> | 給叠代器提供定義和支持 |
C8. 有關算法的頭文件
頭文件 | 描述 |
<algorithm> | 提供一組基於算法的函數,包括置換、排序、合並和搜索 |
<cstdlib> | 聲明C標準庫函數bsearch()和qsort(),進行搜索和排序 |
<ciso646> | 允許在代碼中使用and代替&& |
C9. 有關數值操作的頭文件
頭文件 | 描述 |
<complex> | 支持復雜數值的定義和操作 |
<valarray> | 支持數值矢量的操作 |
<numeric> | 在數值序列上定義一組一般數學操作,例如accumulate和inner_product |
<cmath> | 這是C數學庫,其中還附加了重載函數,以支持C++約定 |
<cstdlib> | 提供的函數可以提取整數的絕對值,對整數進行取余數操作 |
C 有關本地化的頭文件
頭文件 | 描述 |
<locale> | 提供的本地化包括字符類別、排序序列以及貨幣和日期表示。 |
<clocale> | 對本地化提供C樣式支持 |
C++標準庫的所有頭文件都沒有擴展名。C++標準庫以<cname>形式的標準頭文件提供。在 <cname>形式標準的頭文件中,與宏相關的名稱在全局作用域中定義,其他名稱在std命名空間中聲明。在C++中還可以使用name.h 形式的標準C庫頭文件名
1.6模板簡要回顧
- 模板是實現代碼重用機制的一種工具,實質就是實現類型參數化,即把類型定義為參數。
- C++提供兩種模板:函數模板,類模板
函數模板的簡介
- 函數模板就是建立一個通用的函數,其函數返回類型和形參類型不具體指定,而是用虛擬的類型來代表。
- 凡是函數體相同的函數都可以用函數模板來代替,不必定義多個函數,只需在模板中定義一次即可。
- 在調用函數時系統會根據實參的類型來取代模板中的虛擬類型,從而實現了不同函數的功能。
類模板的簡介
- 我們先來看一下下面這個類,求最大值的類
- 和函數模板一樣,類模板就是建立一個通用類,其數據成員的類型、成員函數的返回類型和參數類形都可以不具體指定,而用虛擬的類型來代表。
當使用類模板建立對象時,系統會根據實參的類型取代類模板中的虛擬類型,從而實現不同類的功能。
c++復習:STL之理論基礎