1.STLios
[1]STL容器是直接管理存儲數據。編程
[2]STL適配器是在這些容器上面增長一些操做函數,封裝成一個模板。數組
2.STL 容器app
[1]容器類型:函數
1)array:數組。ui
2)bitset:二進制位操做。spa
3)deque:雙向隊列。code
4)forward_list:單向鏈表。對象
5)list:雙向鏈表。blog
6)map(multimap):map:鍵值非重複容器,multimap:鍵值可重複容器。
7)set(multiset):自動排序非重複集合。
8)vector:動態數組。
9)unordered_set(unordered_multiset):按照hash來存儲的set(multiset)。
10)unordered_map(unordered_multimap):按照hash來存儲的map(multiset)。
[2]容器的分類:
1)容器分爲順序容器和關聯容器。
2)順序容器是不進行自動排序的,關聯容器是按照元素的值進行自動排序的。其中map和set是關聯容器,其餘的是順序容器,最主要的就是關聯容器有find方法,能夠快速查找元素。
[3]順序容器的使用說明:
1)除了array是固定大小外,其餘容器都提供自動內存管理。
2)string和vector保存在連續內存中,所以隨機訪問很快,可是在中間插入刪除會很慢。
3)deque隨機訪問很快,而且在兩端插入刪除很快,可是在中間插入刪除會很慢。
4)list和forward_list在任何地方插入刪除很快,隨機訪問很慢。
[4]關聯容器的使用說明:
1)map的使用,map是一個鍵值對,其中值是一個pair對象:
#include <stdio.h> #include <stdlib.h> #include <string> #include <vector> #include <iostream> #include <algorithm> #include <set> #include <map> #include <arpa/inet.h> using namespace std; class ca { public: int ip; }; class comp{ public: bool operator()(const ca &a, const ca &b) { return a.ip < b.ip; } }; bool operator<(const ca &a, const ca &b) { return a.ip < b.ip; } int main() { //map的第三個參數,另外第三個參數使用普通函數時編譯不過不知怎麼回事 ca a1, a2, a3; map<ca, string> addr2; //使用全局的<運算符重載函數 map<ca, string, comp> addr1; //使用仿函數 addr1.insert(pair<ca, string>(a1, "1 addr a1")); addr2.insert(pair<ca, string>(a1, "2 addr a1")); //pair的使用
pair<ca, string> p1(a1, "1 addr a1"); //建立一個pair對象 addr1.insert(p1);
addr1.insert(pair<ca, string>(a2, "1 addr a2")); //隱式的建立一個pair對象,這個是經常使用的方式,由於一般沒有一個現成的對象 addr1.insert(make_pair(a2, "1 addr a3")); //調用make_pair建立一個pair對象 //關聯容器定義的類型 /* map的元素類型是一個pair對象,這個很重要。 元素: map的元素就是map容器裏面的一個值。就像是set<int>的每一個元素是一個int型對象。 關鍵字: map的關鍵字是pair對象的第一個元素。 */ map<ca, string>::key_type v1; //v1的類型是類ca,表明關鍵字的類型 map<ca, string>::mapped_type v2; //v2的類型是string,表明關鍵字關聯的類型 map<ca, string>::value_type v3; //v3的類型是pair<ca, string>,表明值的類型 set<string>::key_type v4; //v4和v5的類型是string,set的鍵值類型是同樣的 set<string>::value_type v5; return 0; }
2)關鍵字類型必須定義元素的比較方法,這個是確定的,不然沒法進行排序。實際編程中,若是一個類定義了<運算符,就能夠做爲關鍵字了,這個意思就是說關鍵字沒有必要實現>和=運算符,實現了和不實現效果是同樣的。還有就是定義<運算符要符合嚴格弱序的規則,這意思就是自定義的<運算符函數,實現要合理,例如傳給這函數一個(a,b),返回true,傳給一個(b,a),仍是返回true,那就不符合嚴格弱序了。雖然不符合可是不會致使編譯錯誤,只是用的時候會發生各類錯誤,例如set插入了相同的元素。
嚴格弱序規則就是:(1)若是傳入(a,b)返回true,則傳入(b,a)必須返回false。
(2)若是傳入(a,b)返回true,傳入(c,a)返回true,則傳入(c,b)必須返回true。就是說a<b,c<a,則c要小於b。
#include <stdio.h> #include <stdlib.h> #include <string> #include <vector> #include <iostream> #include <algorithm> #include <set> #include <arpa/inet.h> using namespace std; class ca { public: unsigned ip; int port; ca(int ip1, int port1) {ip = ip1; port = port1;} //怎麼定義<運算符都是能夠的,看需求。 //只是定義不一樣時,元素的排序順序是不同的。 //若是用這種方式,則set裏面的排列順序爲: // 1.1.1.1:80 // 1.1.1.1:81 // 1.1.1.2:80 // 1.1.1.2:81 // //這意思就是用ip去比較地址,若是ip不一樣時再用port去比較地址,固然使用這種需求通常用的比較多,這種方讓元素之間有一層優先級。 bool operator<(const ca &other) const{ if(ip < other.ip) return true; else if(other.ip < ip) return false; if(port < other.port) return true; else if(other.port < port) return false; return false; } //徹底等同於上面的函數 bool operator<(const ca &other) const{ if(ip < other.ip ||(ip == other.ip && port <other.port)) return true; return false; } //若是用這種方式,則set裏面的排列順序爲: // 1.1.1.1:80 // 1.1.1.2:80 // 1.1.1.1:81 // 1.1.1.2:81 //這意思就是說但願用ip或port去比較地址,只要有一個小於就是小於,很明顯這種方式用的少。 bool operator<(const ca &other) const { if(ip < other.ip || port < other.port) return true; return false; } //錯誤的方式,錯誤的函數不會致使編譯錯誤,可是處理的時候會發生錯誤。例以下面這種就能夠把相同的數據插入到set裏面。 //很明顯已經違背了嚴格弱序的原則,由於a < b爲true的時候同時b < a也爲true。 bool operator<(const ca &other) const{ return true; } }; int main() { set<ca> v; set<ca>::iterator it; v.insert(ca(inet_addr("1.1.1.1"), 80)); v.insert(ca(inet_addr("1.1.1.1"), 81)); v.insert(ca(inet_addr("1.1.1.2"), 80)); v.insert(ca(inet_addr("1.1.1.2"), 81)); for(it=v.begin(); it!=v.end(); it++) printf("%s:%d\n", inet_ntoa(*((struct in_addr *)&(it->ip))), it->port); return 0; }
3)set的迭代器是const的,就是說不能經過一個set迭代器去修改一個值,這個也是固然的,由於set是有序的,修改了就無序了,同理map的key值也是不能經過迭代器修改的,可是map的value是能夠經過迭代器修改的。
4)map和set的insert操做能夠檢查返回值,判斷是否插入成功,例如元素已經存在則insert會失敗,返回的pair類型的第二個值爲false。
5)lower_bound和upper_bound:這兩個操做都返回一個迭代器,若是關鍵字在容器中,lower_bound返回的迭代器指向第一個元素,upper_bound返回的迭代器指向最後一個位置的以後;若是關鍵字不在容器中,則lower_bound和upper_bound返回相同的位置,這個位置就是不影響排序的關鍵字的插入位置。若是存在則只要(begin=lower_bound;begin!=upper_bound;begin++;)就能夠遍歷這個關鍵字對應的全部元素。若是不存在,則返回的迭代器指向的位置是要查的關鍵字能夠插入的位置。
6)multimap的使用(想必multiset的用法也是差很少的)例:
#include <stdio.h> #include <stdlib.h> #include <string> #include <vector> #include <iostream> #include <algorithm> #include <set> #include <map> #include <arpa/inet.h> using namespace std; /* 查找mulimap關鍵字的方法 */ int main() { // 1.使用lower_bound和upper_bound multimap<int, string> m; multimap<int, string>::iterator begin, end; m.insert(pair<int, string>(1, "boy1")); m.insert(pair<int, string>(2, "girl1")); m.insert(pair<int, string>(2, "girl2")); m.insert(pair<int, string>(2, "girl3")); m.insert(pair<int, string>(5, "dog1")); m.insert(pair<int, string>(5, "dog2")); /* 輸出: key 2 value:girl1 key 2 value:girl2 key 2 value:girl3 end value:dog1 可見begin指向(2, "girl1"),end指向(5, "dog1")。 */ begin = m.lower_bound(2); end = m.upper_bound(2); while(begin != end){ printf("key 2 value:%s\n", begin->second.c_str()); begin++; } printf("end value:%s\n", end->second.c_str()); /* 輸出: begin value:dog1 end value:dog1 可見begin 和end都指向(5, "dog1"),由於此位置就是要查的關鍵字3應該插入的位置。 */ begin = m.lower_bound(3); end = m.upper_bound(3); printf("begin value:%s\n", begin->second.c_str()); printf("end value:%s\n", end->second.c_str()); /* 輸出: begin value:0x7fff4e76b578 end value :0x7fff4e76b578 m.end value:0x7fff4e76b578 可見begin 和end都指向m.end(),由於此位置就是要查的關鍵字10應該插入的位置。 */ begin = m.lower_bound(10); end = m.upper_bound(10); printf("begin value:%p\n", begin); printf("end value:%p\n", end); printf("m.end value:%p\n", m.end()); // 2.使用count方法獲得個數 int count; multimap<int, string>::iterator it; count = m.count(5); //獲得關鍵字5的元素個數 it = m.find(5); //指向關鍵字5的第一個元素 /* 輸出: key 5 value:dog1 key 5 value:dog2 */ while(count > 0){ printf("key 5 value:%s\n", it->second.c_str()); it++; count--; } // 3.使用equal_range pair<multimap<int, string>::iterator, multimap<int, string>::iterator> range; range = m.equal_range(2); //直接獲得關鍵字2的迭代器的起始位置 /* 輸出: key 2 value:girl1 key 2 value:girl2 key 2 value:girl3 */ while(range.first != range.second){ printf("key 2 value:%s\n", range.first->second.c_str()); range.first++; } return 0; }
7)unordered_map和unordered_set:這兩個容器是無序的,就是說不是按順序存儲的。由於map和set都是自動排序的,例如遍歷map或set,能夠獲得按順序排序的值。可是unordered_map和unordered_set是按hash存儲的,遍歷會獲得不按順序輸出的值,因此若是要求存儲的元素有序就用map,若是無序而且須要快速查找,就用unordered_map。map和unordered_map效率比較的例子:
#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <string> #include <vector> #include <iostream> #include <algorithm> #include <set> #include <map> #include <arpa/inet.h> #include <tr1/unordered_map> using namespace std::tr1; using namespace std; double timeuse(struct timeval begin, struct timeval end) { double res; if(end.tv_usec < begin.tv_usec){ end.tv_usec += 1000000; end.tv_sec--; } res = end.tv_usec - begin.tv_usec; res += (end.tv_sec - begin.tv_sec)*1000000; return res; } int main() { int i; map<int, int> m; map<int, int>::iterator it; unordered_map<int, int> um; unordered_map<int, int>::iterator uit; struct timeval tv_begin, tv_end; double res; #define BEGIN gettimeofday(&tv_begin, NULL); #define END(s) do{\ gettimeofday(&tv_end, NULL); \ res = timeuse(tv_begin, tv_end); \ printf("%-30s, usetime:%f usec [%f sec]\n", s, res, res/1000000);\ }while(0) BEGIN for(i=0; i<10000000; i++) m.insert(pair<int, int>(i, i)); END("map insert"); BEGIN for(i=0; i<10000000; i++) um.insert(pair<int, int>(i, i)); END("unordered_map insert"); BEGIN it = m.find(500000); END("map find"); BEGIN uit = um.find(500000); END("unordered_map find"); return 0; }
輸出:
map insert , usetime:10102899.000000 usec [10.102899 sec] unordered_map insert , usetime:2749505.000000 usec [2.749505 sec] map find , usetime:3.000000 usec [0.000003 sec] unordered_map find , usetime:1.000000 usec [0.000001 sec]
因而可知unordered_map在插入和查找方面仍是比map要快不少的,固然內存佔用的也多。
3.STL適配器
[1]stack:棧適配器。這個要注意的就是棧裏面是有一個容器來存儲元素的,常規的理解棧應該就是一個數組,其實不是,棧默認的容器是一個雙向隊列(deque),棧也能夠用vector、list等做爲元素的容器,有個條件就是容易須要提供push_back()、back()、和pop_back()方法,由於set沒有提供這些方法,因此不能把set做爲棧的容器。所謂棧就是在一個容器上面加了一些操做函數,封裝成了棧模板(STL中棧定義:template < class T, class Container = deque<T> > class stack;)。
[2]queue:單向隊列適配器。這個和stack是同樣的,特色是先進先出。固然也是須要提供一個容器來存儲元素,默認是deque。
[3]priority_queue :優先級隊列適配器。這個適配器是把容器內的元素排序好的,每次能夠獲取優先級最高的元素。因此能夠傳入一個優先級比較函數,默認比較函數是<,默認的容器是vector,定義方式priority_queue<Type, Container, Functional>。其實這個適配器只是在queue上面加了一個優先級排序函數。
4.STL具體用法
[1]const_iterator:若是不須要寫訪問容器時,應該使用const_iterator迭代器,方法和iterator是同樣的。
[2]reverse_iterator(const_reverse_iterator):能夠從後向前遍歷容器。
[3]管理容量:除了array以外,容器的內存都是自動管理的。size()表示當前的元素數量,capacity()表示已經預分配的容量,reserve()表示設置預分配的容量。這個意思就是說capacity()是已經預分配好的容量,不論是程序自動分配仍是手動調用reserve()分配。還有就是resize()是設置容器使用的大小,和預分配沒有關係,例如當前元素個數是5,則resize(8)會往容器增長3個元素,resize(4)會刪除1個元素。
[4]substr:拷貝原始string的一部分或所有。另外string類還提供了一些其餘方法,來完成和char *類型的字符串的處理函數,例如相似strstr、strrstr的函數。
舉例:
#include <stdio.h> #include <stdlib.h> #include <string> #include <vector> #include <iostream> #include <algorithm> #include <array> using namespace std; int main() { vector<int> v; vector<int>::const_iterator c_it; vector<int>::const_reverse_iterator cr_it; v.push_back(1); v.push_back(2); v.push_back(3);v.push_back(4);v.push_back(5); //iterator對應的是begin、end for(c_it = v.begin(); c_it!= v.end(); c_it++) printf("%d\n", *c_it); //reverse_iterator對應的是rbegin、rend,cr_it = v.begin()是編譯不過的 for(cr_it = v.rbegin(); cr_it!= v.rend(); cr_it++) printf("%d\n", *cr_it); // 容量設置 printf("size: %u\n", v.size()); printf("capacity:%u\n", v.capacity()); //程序自動預分配的容量,例如值是8 printf("--------------------------\n"); v.reserve(20); //手動設置預分配的容量,若是值小於已經自動預分配的容量則不生效 printf("size: %u\n", v.size()); printf("capacity:%u\n", v.capacity()); //此時值就是20了 printf("--------------------------\n"); v.resize(200); //強制設置元素個數是200 printf("size: %u\n", v.size()); //值是200 printf("capacity:%u\n", v.capacity()); //超過預分配的容量後,程序就會再次自動預分配 //string操做 string src("test string"); string dst; // substr(pos, n) pos默認是0,n默認是總長度,因此只傳一個參數的時候實際上是指定了拷貝的起始位置 dst = src.substr(3); printf("dst:%s\n", dst.c_str()); // dst:"t string" dst = src.substr(); printf("dst:%s\n", dst.c_str()); // dst:"test string" return 0; }
5.C++手冊
http://www.cplusplus.com/reference/