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>
此外,C++的STL還包括仿函數、適配器以及空間適配器。
2.STL的優勢
- STL是C++的一部分,因此不用額外安裝什么,它被內建在你的編譯器之內。
- STL的一個重要特點是數據結構和算法的分離。盡管這是個簡單的概念,但是這種分離確實使得STL變得非常通用。例如,在STL的vector容器中,可以放入元素(對象)、基礎數據類型變量、指針;STL的sort()函數可以用來操作vector,list等容器。
- 程序員可以不用思考STL具體的實現過程,只要能夠熟練使用STL就OK了。這樣他們就可以把精力放在程序開發的別的方面。
- STL具有高可重用性,高性能,高移植性,跨平臺的優點。
- STL有以下這些好處,我們知道STL無疑是最值得C++程序員驕傲的一部分。每一個C++程序員都應該好好學習STL。只有能夠熟練使用STL的程序員,才是好的C++程序員。
高可重用性: STL中幾乎所有的代碼都采用了模板類和模版函數的方式實現,這相比于傳統的由函數和類組成的庫來說提供了更好的代碼重用機會。
高性能:如map可以高效地從十萬條記錄里面查找出指定的記錄,因為map是采用紅黑樹的變體實現的。(紅黑樹是平橫二叉樹的一種)
高移植性:如在項目A上用STL編寫的模塊,可以直接移植到項目B上。
跨平臺:如用windows的Visual Studio編寫的代碼可以在Mac OS的XCode上直接編譯。
3.容器
在實際的開發過程中,數據結構本身的重要性不會遜于操作于數據結構的算法的重要性,當程序中存在著對時間要求很高的部分時,數據結構的選擇就顯得更加重要。
經典的數據結構數量有限,但是我們常常重復著一些為了實現向量、鏈表等結構而編寫的代碼,這些代碼都十分相似,只是為了適應不同數據的變化而在細節上有所出入。STL容器就為我們提供了這樣的方便,它允許我們重復利用已有的代碼實現構造自己的特定類型下的數據結構,通過設置一些模板,STL容器對最常用的數據結構提供了支持,這些模板的參數允許我們指定容器中元素的數據類型,可以將我們許多重復而乏味的工作簡化。
在C++ 中容器被定義為:在數據存儲上,有一種對象類型,它可以持有其它對象或指向其它對象的指針,這種對象類型就叫做容器。
容器部分主要由頭文件<vector>,<list>,<deque>,<set>,<map>,<stack> 和<queue>
組成
容器的分類:
標準C++的STL框架中的容器主要有兩大類:
序列式容器(Sequence containers): 將一組具有相同類型T的對象,以嚴格的線性形式組織在一起。
每個元素都有固定位置--取決于插入時機和地點,和元素值無關。如:
vector(向量)、deque(double-ended queue雙端隊列)、list(表)
序列容器可以視為數組和鏈表的推廣。
關聯式容器(Associated containers): 關聯容器的特點是(鍵)有序的,即元素是按預定義的鍵順序(如升序)插入的。
元素位置取決于特定的排序準則,和插入順序無關 :
set<Key>(集合)multiset<Key>(多重集合)map<Key, T>(映射/映像)multimap<Key, T>(多重映射)hash_set<Key, H>(散列集)hash_map<Key, T, H>(散列映射)hash_multimap<Key, T, H>(散列多映射)
容器適配器(container adapter)不是獨立的容器,只是某種容器的變種,它提供原容器的一個專用的受限接口。特別是,容器適配器不提供迭代器。
stack<T>(棧)queue<T>(隊列)priority_queue<T>(優先隊列)
4.迭代器
軟件設計有一個基本原則,所有的問題都可以通過引進一個間接層來簡化,這種簡化在STL中就是用迭代器來完成的。概括來說,迭代器在STL中用來將算法和容器聯系起來,起著一種黏和劑的作用。幾乎STL提供的所有算法都是通過迭代器存取元素序列進行工作的,每一個容器都定義了其本身所專有的迭代器,用以存取容器中的元素。
迭代器部分主要由頭文件<utility>,<iterator>和<memory>
組成。<utility>
是一個很小的頭文件,它包括了貫穿使用在STL中的幾個模板的聲明,<iterator>
中提供了迭代器使用的許多方法,而對于<memory>
的描述則十分的困難,它以不同尋常的方式為容器中的元素分配存儲空間,同時也為某些算法執行期間產生 的臨時對象提供機制,<memory>
中的主要部分是模板類allocator,它負責產生所有容器中的默認分配器。
簡單來說,迭代器就是一個指針,指向具體容器中的具體元素,解引用以后的數據類型就是容器元素的數據類型。是容器和算法的粘合劑,是一個間接層。
5.算法
函數庫對數據類型的選擇對其可重用性起著至關重要的作用。舉例來說,一個求方根的函數,在使用浮點數作為其參數類型的情況下的可重用性肯定比使用整型作為它的參數類性要高。而C++通過模板的機制允許推遲對某些類型的選擇,直到真正想使用模板或者說對模板進行特化的時候,STL就利用了這一點提 供了相當多的有用算法。它是在一個有效的框架中完成這些算法的——可以將所有的類型劃分為少數的幾類,然后就可以在模版的參數中使用一種類型替換掉同一種類中的其他類型。
STL提供了大約100個實現算法的模版函數,比如算法for_each將為指定序列中的每一個元素調用指定的函數,stable_sort以 你所指定的規則對序列進行穩定性排序等等。這樣一來,只要熟悉了STL之后,許多代碼可以被大大的化簡,只需要通過調用一兩個算法模板,就可以完成所需要 的功能并大大地提升效率。
算法部分主要由頭文件,和組 成。是所有STL頭文件中最大的一個(盡管它很好理解),它是由一大堆模版函數組成的,可以認為每個函數在很大程度上都是獨立的,其中常用到的功能范圍涉及到比較、交換、查找、遍歷操作、復制、修改、移除、反轉、排序、合并等等。體積很小,只包括幾個在序列上面進行簡單數學運算的模板函數,包括加法和乘法在序列上的一些操作。中則定義了一些模板類,用以聲明函數對象。
說白了就是一系列的函數集合,這些函數通常是模板函數。
代碼示例
#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void func1()
{// 定義一個容器:用來存數據、存 int 數據vector<int> a;a.push_back(1);a.push_back(2);a.push_back(1);a.push_back(3);a.push_back(1);a.push_back(4);a.push_back(1);a.push_back(5);// 迭代器,提供了遍歷容器的統一方法//vector<int>::iterator it;//for (it = a.begin(); it != a.end(); it++)//{// cout << *it << " ";//}//cout << endl;vector<int>::iterator it = a.begin();while (it != a.end()){cout << *it << " ";it++;}cout << endl;// 算法:用來處理容器中的數據,通過迭代器int num = count(a.begin(), a.end(), 1);cout << num << endl;
}class Student
{
public:Student (int id, int age){this->id = id;this->age = age;}void print(){printf ("id = %d, age = %d\n", id, age);}
private:int id;int age;
};void func2()
{Student s1(10,20);Student s2(11,21);Student s3(12,22);Student s4(13,23);Student s5(14,24);vector<Student> v;v.push_back(s1);v.push_back(s2);v.push_back(s3);v.push_back(s4);v.push_back(s5);vector<Student>::iterator it = v.begin();while (it != v.end()){it->print();it++;}
}void func3()
{Student s1(10,20);Student s2(11,21);Student s3(12,22);Student s4(13,23);Student s5(14,24);vector<Student*> v;
// v.push_back(&s1);
// v.push_back(&s2);
// v.push_back(&s3);
// v.push_back(&s4);
// v.push_back(&s5);v.push_back(new Student(10,20));v.push_back(new Student(11,21));v.push_back(new Student(12,22));v.push_back(new Student(13,23));v.push_back(new Student(14,24));vector<Student*>::iterator it = v.begin();while (it != v.end()){(*it)->print();it++;}
}int main()
{// func1();// func2();func3();return 0;
}