STL理論基礎、容器、迭代器、演算法
一、STL基本概念
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優點:
- STL是C++的一部分,因此不用額外安裝什麼,它被內建在你的編譯器之內。
- STL的一個重要特點是資料結構和演算法的分離。儘管這是個簡單的概念,但是這種分離確實使得STL變得非常通用。例如,在STL的vector容器中,可以放入元素、基礎資料型別變數、元素的地址;STL的sort()函式可以用來操作vector,list等容器。
- 程式設計師可以不用思考STL具體的實現過程,只要能夠熟練使用STL就OK了。這樣他們就可以把精力放在程式開發的別的方面。
- STL具有高可重用性,高效能,高移植性,跨平臺的優點。
- 高可重用性:STL中幾乎所有的程式碼都採用了模板類和模版函式的方式實現,這相比於傳統的由函式和類組成的庫來說提供了更好的程式碼重用機會。
- 高效能:如map可以高效地從十萬條記錄裡面查找出指定的記錄,因為map是採用紅黑樹的變體實現的。(紅黑樹是平橫二叉樹的一種)
- 高移植性:如在專案A上用STL編寫的模組,可以直接移植到專案B上。
- 跨平臺:如用windows的Visual Studio編寫的程式碼可以在Mac OS的XCode上直接編譯。
二、三大元件介紹
1、容器
STL中容器是指儲存有限資料元素的一種資料結構。在使用容器之前首先要根據自己使用的資料集和將要對資料結構採取的訪問模式,比如增刪改查,決定使用STL中的何種容器型別。
STL對定義的通用容器分三類:順序容器、關聯容器和容器介面卡。
順序容器:此種容器元素的位置是由進入容器的時間和地點決定的;
關聯容器:此種容器已經有規則,進入容器的元素的位置不是由進入容器的時間和地點決定的;
2、迭代器
我們使用容器的時候,迭代器是一個不可分割的部分。迭代器在STL中用來將演算法和容器聯絡起來,起著一種膠著劑的作用。迭代器是一種檢查容器內元素並遍歷元素的資料型別。迭代器是一種行為類似指標的物件,它提供類似指標的功能,對容器成員的內容進行訪問。
注意:每個迭代器是和每一個容器繫結的。
3、演算法
通過有限步驟,解決問題。
STL提供了大約100個實現演算法的模版函式,比如演算法for_each將為指定序列中的每一個元素呼叫指定的函式,stable_sort以你所指定的規則對序列進行穩定性排序等等。這樣一來,只要熟悉了STL之後,許多程式碼可以被大大的化簡,只需要通過呼叫一兩個演算法模板,就可以完成所需要的功能並大大地提升效率。
C++通過模板的機制允許推遲對某些型別的選擇,直到真正想使用模板或者說對模板進行特化的時候,STL就利用了這一點提供了相當多的有用演算法。
演算法部分主要由標頭檔案<algorithm>,<numeric>和<functional>組成。<algorithm>是所有STL標頭檔案中最大的一個(儘管它很好理解),它是由一大堆模版函式組成的,可以認為每個函式在很大程度上 都是獨立的,其中常用到的功能範圍涉及到比較、交換、查詢、遍歷操作、複製、修改、移除、反轉、排序、合併等等。<numeric>體積很小,只包括幾個在序列上面進行簡單數學運算的模板函式,包括加法和乘法在序列上的一些操作。<functional>中則定義了一些模板類,用以宣告函式物件。
三、案例:
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; //演算法:負責統計某個元素的個數 int mycount(int* start, int* end, int val) { int num = 0; while (start != end) { if (*start == val) { num++; } start++; } return num; } int main(void) { //陣列 容器 int arr[] = { 0,1,2,8,7,9,0 }; int* pStart = arr;//指向元素的第一個元素 int* pEnd = &(arr[sizeof(arr) / sizeof(int)]); int num = mycount(pStart, pEnd, 2); cout << "num:" << num << endl; return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include<vector>//動態陣列 可變陣列 #include<algorithm>//演算法 using namespace std; void PrintVector(int v) { cout << v << " " ; } //STL基本語法 void test01() { //定義一個容器,並且指定這個容器存放的元素型別為int vector<int> v; v.push_back(10); v.push_back(20); v.push_back(30); v.push_back(40); //通過STL提供的for_each演算法 //容器提供的迭代器 //vector<int>::iterator 迭代器型別 vector<int>::iterator pBegin = v.begin();//第一個元素的位置 vector<int>::iterator pEnd = v.end();//最後一個元素的下一個的位置 //容器中可能存放基礎的資料型別,也可能存放自定義的資料型別 for_each(pBegin, pEnd, PrintVector); cout << endl; } //容器也可存放自定義的資料型別 class Person { public: Person(int age,int id):age(age),id(id){} public: int age; int id; }; void test02() { //建立容器,並且指定容器的元素型別是Person vector<Person> v; Person p1(10, 20), p2(30, 40), p3(50, 60); v.push_back(p1); v.push_back(p2); v.push_back(p3); //遍歷 for (vector<Person>::iterator it = v.begin(); it != v.end();it++) { cout << (*it).age << " " << (*it).id << endl; } } //容器存放Person型別指標,並且for_each列印 或者 迭代器方式 void test03() { //建立容器,並且指定容器的元素型別是Person* vector<Person*> v1; Person p1(1, 2), p2(3, 4), p3(5, 6); v1.push_back(&p1); v1.push_back(&p2); v1.push_back(&p3); //遍歷 for (vector<Person*>::iterator it = v1.begin(); it != v1.end();it++) { cout << (**it).age << " " << (**it).id << endl; } } // 容器巢狀容器 一個容器作為另一個容器的元素 void PrintVectorNest(vector<int> v) { vector<int>::iterator pBegin = v.begin(); vector<int>::iterator pEnd = v.end(); for_each(pBegin, pEnd, PrintVector); } typedef vector<int>(VECTOR); void test04() { vector<vector<int>> v_nest; vector<int> v1; v1.push_back(100); v1.push_back(200); v1.push_back(300); v1.push_back(400); vector<int> v2; v2.push_back(110); v2.push_back(120); v2.push_back(130); v2.push_back(140); v_nest.push_back(v1); v_nest.push_back(v2); vector<VECTOR>::iterator pBegin = v_nest.begin(); vector<VECTOR>::iterator pEnd = v_nest.end(); for_each(pBegin, pEnd, PrintVectorNest); cout << endl; } int main(void) { test01(); test02(); test03(); test04(); return 0; }