STL學習
1.順序容器
順序容器是將單一型別元素聚集起來成為容器,然後根據位置來儲存和訪問這些元素。標準庫常用順序容器如下:
- vector,可變大小陣列。支援快速隨機訪問,在尾部之外的位置插入或刪除元可能很慢。
- deque,雙端佇列。支援快速隨機訪問,在頭尾部插入速度很快。
- list,雙向連結串列。只支援雙向順序訪問,在list中任何位置插入刪除都很快。
- forward_list,單向連結串列。只支援單向順序訪問,在連結串列任何位置插入刪除都很快。
容器只定義了少量操作,大多數額外操作則有演算法庫提供。容器型別的操作集合具有以下層次結構特點:一些操作適用於所有容器型別;另外一些操作則只適用於順序或關聯容器型別;還有一些操作只適用於順序或關聯容器型別的一個子集。
1.1 順序容器定義與初始化
所有的容器都是類模版,要定義某種特殊的容器,必須在容器後的尖括號內提供存放元素的資料型別。容器元素型別必須滿足以下兩個約束:元素型別必須支援賦值運算;元素型別的物件必須可以複製。所有容器型別都定義了預設建構函式,用於建立指定型別的空容器物件。除了預設建構函式,容器型別還提供其他的建構函式,使程式設計師可以指定元素初值。在C++11中,我們可以對容器進行列表初始化。
vector<string> svec; //預設建構函式
vector<string> svec2(svec); //將一個容器複製給另一個容器時,型別必須匹配
list<string> slist(svec.begin(), svec.end()); //初始化為一段元素的副本
const list<int>::size_type list_size = 64;
list<string> slist(list_size, "eh"); //分配和初始化指定數目的元素
list<string> authors = {"Qin","Li"}; //C++11列表初始化
1.2 順序容器的常用操作
1.2.1 新增元素
vector<string> container;
string text_word;
while (cin >> text_word)
container.push_back(text_word);
list<int> ilist;
for (size_t ix = 0; ix != 4; ++ix)
ilist.push_front(ix);
任何insert或push操作都可能導致迭代器失效。當編寫迴圈將元素插入到vector或deque容器中時,程式必須確保迭代器在每次迴圈後都得到更新。為了避免儲存end迭代器,可以在每次做完插入運算後重新計算end迭代器值:
vector<int>::iterator first = v.begin();//不要令last = v.end();
while (first != v.end())
{
first = v.insert(first, 42); // insert new value
++first; // advance first just past the element we added
}
1.2.2 新增元素
vector<string> container;
string text_word;
while (cin >> text_word)
container.push_back(text_word);
list<int> ilist;
for (size_t ix = 0; ix != 4; ++ix)
ilist.push_front(ix);
任何 insert 或 push 操作都可能導致迭代器失效。當編寫迴圈將元素插入到 vector 或 deque 容器中時,程式必須確保迭代器在每次迴圈後都得到更新。為了避免儲存 end 迭代器,可以在每次做完插入運算後重新計算 end 迭代器值:
vector<int>::iterator first = v.begin();//不要令last = v.end();
while (first != v.end())
{
first = v.insert(first, 42); // insert new value
++first; // advance first just past the element we added
}
1.2.3 順序容器大小的操作
為避免每次新增元素都會執行記憶體分配和釋放的操作,vector和string每次獲取新的記憶體空間時,都會分配比需求更大的空間作為備用,以此減少記憶體分配的次數。
vector<int> c(10,2);
int a = c.size(); //返回容器c中的元素個數
bool b = c.empty(); //判斷容器是否為空
c.reserve(20) //分配至少能容納20個元素的記憶體空間
c.capacity() //返回容器可以容納的元素個數
c.resize(15) //
1.2.4 刪除元素
pop_front 和 pop_back 函式的返回值並不是刪除的元素值,而是 void。要獲取刪除的元素值,則必須在刪除元素之前呼叫 front 或 back 函式。
while (!ilist.empty()) {
process(ilist.front()); // do something with the current top of ilist
ilist.pop_front(); // done; remove first element
}
erase 操作不會檢查它的引數,因此必須確保用作引數的迭代器或迭代器範圍是有效的。通常,程式設計師必須在容器中找出要刪除的元素後,才使用 erase 操作。尋找一個指定元素的最簡單方法是使用標準庫的 find 演算法。
string searchValue("Quasimodo");
list<string>::iterator iter = find(slist.begin(), slist.end(), searchValue);
if (iter != slist.end()) slist.erase(iter);
1.3 容器介面卡
標準庫來提供了三種容器介面卡。實際上,介面卡是根據原始的容器型別所提供的操作,通過定義新的操作介面,來適應基礎的容器型別。順序容器介面卡包括stack、queue和priority_queue型別。
棧的常用操作:
- empty,判斷棧是否為空,為空則返回true。
- size,返回棧中元素個數。
- pop,刪除棧頂元素,但不返回其值。
- top,返回棧頂元素的值。
- push,在棧頂壓入新元素。
佇列的常用操作:
- empty,size 同棧
- pop,刪除隊首元素,但不返回其值。
- push,在隊尾壓入一個新元素。
- front,返回隊首元素。
- back,返回隊尾元素。
2. 關聯容器
關聯容器支援通過鍵來高效地查詢和讀取元素,兩個基本的關聯容器型別是map和set。map的元素以鍵-值(key-value)對的形式組織:鍵用於元素在map中的索引,而值則表示所儲存和讀取的資料。set僅包含一個鍵,並有效地支援關於某個鍵是否存在的查詢。map可理解為字典,set可理解為一類元素的集合。
關聯容器和順序容器的本質差別在於:關聯容器通過鍵(key)儲存和讀取元素,而順序容器則通過元素在容器中的位置順序儲存和訪問元素。
set 和 map 型別的物件所包含的元素都具有不同的鍵,不允許為同一個鍵新增第二個元素。如果一個鍵必須對應多個例項,則需使用 multimap 或 multi set,這兩種型別允許多個元素擁有相同的鍵。
2.1 pair型別
pair 包含兩個資料值。在建立 pair 物件時,必須提供兩個型別名:pair 物件所包含的兩個資料成員各自對應的型別名字。如果在建立 pair 物件時不提供初始化式,則呼叫預設建構函式對其成員採用值初始化。
pair <string, int> word_count;
typedef pair<string, string> Author; //利用 typedef 簡化其宣告
Author joyce("James", "Joyce");
與其他標準庫型別不同,對於 pair 類,可以直接訪問其資料成員:其成員都是僅有的,分別命名為 first 和 second。只需使用普通的點操作符(成員訪問標誌)即可訪問其成員:
string firstBook;
if (author.first == "James" && author.second == "Joyce")
firstBook = "Stephen Hero";
除了建構函式,標準庫還定義了一個 make_pair 函式,由傳遞給它的兩個實參生成一個新的 pair 物件。可如下使用該函式建立新的 pair 物件,並賦給已存在的 pair 物件:
pair<string, string> next_auth;
string first, last;
while (cin >> first >> last) {
next_auth = make_pair(first, last);
}
2.2 map型別
map 物件的元素是鍵-值對,也即每個元素包含兩個部分:鍵以及由鍵關聯的值。map 的 value_type 就反映了這個事實。該型別比前面介紹的容器所使用的元素型別要複雜得多:value_type 是儲存元素的鍵以及值的 pair 型別,而且鍵為 const。例如,word_count 陣列的 value_type 為 pair<const string, int> 型別。
map <string,int> word_count;
word_count.insert( make_pair("James", "Joyce") );
map<string, int>::iterator map_it = word_count.begin();
cout << map_it->first;
cout << " " << map_it->second;
2.2.1 給map新增元素
map容器中新增鍵-值元素對,可使用 insert 成員實現;或者,先用下標操作符獲取元素,然後給獲取的元素賦值。在這兩種情況下,一個給定的鍵只能對應於一個元素這一事實影響了這些操作的行為。
用下標操作符來獲取該鍵所關聯的值。如果該鍵已在容器中,則返回該鍵所關聯的值。只有在所查詢的鍵不存在時,map 容器才為該鍵建立一個新的元素,並將它插入到此 map 物件中。此時,所關聯的值採用值初始化:類型別的元素用預設建構函式初始化,而內建型別的元素初始化為 0。
map<string, int> word_count; // empty map from string to int
string word;
while (cin >> word)
++word_count[word];
使用下標給 map 容器新增新元素時,元素的值部分將採用值初始化。通常,我們會立即為其賦值,其實就是對同一個物件進行初始化並賦值。而插入元素的另一個方法是:直接使用 insert 成員,其語法更緊湊:
word_count.insert(map<string, int>::value_type("Anna", 1));
word_count.insert(make_pair("Anna", 1));
map 物件中一個給定鍵只對應一個元素。如果試圖插入的元素所對應的鍵已在容器中,則 insert 將不做任何操作。但是,帶有一個鍵-值 pair 形參的 insert 版本將返回一個值:包含一個迭代器和一個 bool 值的 pair 物件,其中迭代器指向 map 中具有相應鍵的元素,而 bool 值則表示是否插入了該元素。如果該鍵已在容器中,則其關聯的值保持不變,返回的 bool 值為 true。在這兩種情況下,迭代器都將指向具有給定鍵的元素。
map<string, int> word_count;
string word;
while (cin >> word) {
// inserts element with key equal to word and value 1;
// if word already in word_count, insert does nothing
pair<map<string, int>::iterator, bool> ret =
word_count.insert(make_pair(word, 1));
if (!ret.second) // word already in word_count
++ret.first->second; // increment counter
}
2.2.2 查詢並讀取map中的元素
不能使用下標來查詢map中的某一元素是否存在,因為如果該鍵不在 map 容器中,那麼下標操作會插入一個具有該鍵的新元素。map 容器提供了兩個操作:count 和 find,用於檢查某個鍵是否存在而不會插入該鍵。
對於 map 物件,count 成員的返回值只能是 0 或 1。map 容器只允許一個鍵對應一個例項,所以 count 可有效地表明一個鍵是否存在。find 操作返回指向元素的迭代器,如果元素不存在,則返回 end 迭代器。
int occurs = 0;
map <string, int>::iterator it = word_count.find("foobar");
if(it != wor_count.end() )
occurs = it->second;
2.2.3 從map物件中刪除元素
if (word_count.erase(removal_word))
cout << "ok: " << removal_word << " removed\n";
else cout << "oops: " << removal_word << " not found!\n";
2.2.4 map物件的迭代遍歷
與其他容器一樣,map 同樣提供 begin 和 end 運算,以生成用於遍歷整個容器的迭代器。例如,可如下將 map 容器 word_count 的內容輸出:
map<string, int>::const_iterator it = word_count.begin();
while(it != word_count.end()){
cout<< it->first <<" occurs "
<< it->second << " times " <<endl;
++it;
}
2.3 set型別
map 容器是鍵-值對的集合,好比以人名為鍵的地址和電話號碼。相反地,set 容器只是單純的鍵的集合。例如,某公司可能定義了一個名為 bad_checks 的 set 容器,用於記錄曾經給本公司發空頭支票的客戶。當只想知道一個值是否存在時,使用 set 容器是最適合的。例如,在接收一張支票前,該公司可能想查詢 bad_checks 物件,看看該客戶的名字是否存在。
set 容器支援大部分的 map 操作,包括上面描述的建構函式、 insert 操作、 count 和 find 操作、 erase 操作等。但是, 不支援下標操作符,而且沒有定義 mapped_type 型別。在 set 容器中,value_type 不是 pair 型別,而是與 key_type 相同的型別。它們指的都是 set 中儲存的元素型別。這一差別也體現了 set 儲存的元素僅僅是鍵,而沒有所關聯的值。與 map 一樣,set 容器儲存的鍵也必須唯一,而且不能修改。
vector<int> ivec;
for( vector<int>::size_type i = 0; i !=10; ++i){
ivec.push_back(i);
ivec.push_back(i);
}
set<int> iset(ivec.begin(), ivec.end());
cout << ivec.size() << endl; // prints 20
cout << iset.size() << endl; // prints 10
set<string> set1;
set1.insert("the");
set<int> iset2;
iset2. insert( ivec.begin(), ivec.end() ); // iset2 has 10 elements
iset.find(1); // returns iterator that refers to the element with key == 1
iset.find(11); // returns iterator == iset.end()
iset.count(1); // returns 1
set<int>::iterator set_it = isec.find(1);
cout<< *set_it <<endl;
正如不能修改 map 中元素的鍵部分一樣,set 中的鍵也為 const。在獲得指向 set 中某元素的迭代器後,只能對其做讀操作,而不能做寫操作。
2.4 multimap 和 multiset 型別
map 和 set 容器中,一個鍵只能對應一個例項。而 multiset 和 multimap 型別則允許一個鍵對應多個例項。例如,在電話簿中,每個人可能有單獨的電話號碼列表。在作者的文章集中,每位作者可能有單獨的文章標題列表。multimap 和 multiset 型別與相應的單元素版本具有相同的標頭檔案定義:分別是 map 和 set 標頭檔案。
multimap 和 multiset 所支援的操作分別與 map 和 set 的操作相同,只有一個例外:multimap 不支援下標運算。不能對 multimap 物件使用下標操作,因為在這類容器中,某個鍵可能對應多個值。為了順應一個鍵可以對應多個值這一性質,map 和 multimap,或 set 和 multiset 中相同的操作都以不同的方式做出了一定的修改。在使用 multimap 或 multiset 時,對於某個鍵,必須做好處理多個值的準備,而非只有單一的值。
由於鍵不要求是唯一的,因此每次呼叫 insert 總會新增一個元素。
帶有一個鍵引數的 erase 版本將刪除擁有該鍵的所有元素,並返回刪除元素的個數。而帶有一個或一對迭代器引數的版本只刪除指定的元素,並返回 void 型別。
關聯容器 map 和 set 的元素是按順序儲存的, multimap 和 multset 也一樣。因此,在 multimap 和 multiset 容器中,如果某個鍵對應多個例項,則這些例項在容器中將相鄰存放。 在 multimap 和 multiset 中查詢元素有三種策略,而且三種策略都基於一個事實——在 multimap 中,同一個鍵所關聯的元素必然相鄰存放。
- 使用 find 和 count 操作
- lower_bound 和 upper_bound
- enual_range 函式
equal_range 函式返回儲存一對迭代器的 pair 物件。如果該值存在,則 pair 物件中的第一個迭代器指向該鍵關聯的第一個例項,第二個迭代器指向該鍵關聯的最後一個例項的下一位置。如果找不到匹配的元素,則 pair 物件中的兩個迭代器都將指向此鍵應該插入的位置。
pair<authors_it, authors_it> pos = authors.equal_range(search_item);
while (pos.first != pos.second) {
cout << pos.first->second << endl;
++pos.first;
}
3. 常用泛型演算法
標準庫為容器型別定義的操作很少,並沒有為每個容器實現更多的操作。因為這部分操作可以抽象出來為所有的容器工作,那就是泛型演算法。所謂“泛型”是指這些演算法可以應用於多種容器型別上,而容器內的元素型別也可以多樣化。標準庫提供了100多個泛型演算法,主要定義於標頭檔案<algorithm>中,還有一組泛化的算術演算法定義於標頭檔案<numeric>中。
大多數泛型演算法是工作於容器的一對迭代器所標識的範圍,並完全通過迭代器來實現其功能。這段由迭代器指定的範圍稱為“輸入範圍”。帶有輸入範圍引數的演算法總是使用前兩個引數標記該範圍,分別指向要處理的第一個元素和最後一個元素的下一個位置。
3.1 查詢
find 和 count 演算法在輸入範圍中查詢指定值。find 演算法返回引用第一個匹配元素的迭代器,count 演算法返回元素在輸入序列中出現次數的計數。
find(beg, end, val)
count(beg, end, val)
在輸入範圍中查詢等於 val 的元素,使用基礎型別的相等(==)操作符。find 返回第一個匹配元素的迭代器,如果不存在在匹配元素就返回 end。count 返回 val 出現次數的計數。
find函式的原始碼如下:
template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& val)
{
while(first != last){
if(*first == val) return first;
++first;
}
return last;
}
一個例子,查詢陣列中的某個值。由於指標就像內建陣列上的迭代器一樣,因此可以用find在陣列中查詢值。使用begin和end函式可以獲取指向陣列首尾元素的指標。
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int myints[]={ 10, 20, 30, 40 };
int* p;
p=find(begin(myints), end(myints), 30);
if(p!=myints+4)
cout<<*p<<endl;
}
3.2 排序
c++中最經常使用的演算法應該就是排序演算法,也就是sort函式。當然還有partial_sort以及stable_sort。sort函式排序預設是從小到大,如果想給自定義型別排序,可以過載運算子或者自定義比較函式。
升序:sort(begin,end,less<data-type>());
降序:sort(begin,end,greater<data-type>()).
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
int a[10]={2,4,1,23,5,76,0,43,24,65},i;
for(i=0;i<10;i++) cout<<a[i]<<" ";
cout<<endl;
sort(a,a+10,greater<int>());
for(i=0;i<10;i++) cout<<a[i]<<" ";
cout<<endl;
}
當然,也可以自己寫比較函式
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct Data
{
char data[100];
}str[100];
bool cmp(const Data &elem1, const Data &elem2)
{
if (strcmp(elem1.data, elem2.data) < 0)
return true;
return false;
}
int main()
{
int n, i;
while (cin>>n)
{
for (i=0; i<n; ++i)
{
cin>>str[i].data;
}
sort(str, str+n, cmp);
for (i=0; i<n; ++i)
cout<<str[i].data<<endl;
}
return 0;
}
3.3 去重unique
unique的作用是從輸入序列中刪除”所有相鄰的重複元素。該演算法刪除相鄰的重複元素,然後重新排列輸入範圍內的元素,並且返回一個迭代器(容器的長度沒變,只是元素順序改變了),表示無重複的值範圍的結束。
sort(words.begin(), words.end()); //排序
vector<string>::iterator end_unique = unique(words.begin(), words.end()); //去重
words.erase(end_unique, words.end()); //刪除結尾元素
在STL中unique函式是一個去重函式, unique的功能是去除相鄰的重複元素(只保留一個),其實它並不真正把重複的元素刪除,是把重複的元素移到後面去了,然後依然儲存到了原陣列中,然後 返回去重後最後一個元素的地址,因為unique去除的是相鄰的重複元素,所以一般用之前都會要排一下序。
原始碼如下:
template <class ForwardIterator>
ForwardIterator unique (ForwardIterator first, ForwardIterator last)
{
if (first==last) return last;
ForwardIterator result = first;
while (++first != last){
if (!(*result == *first)) *(++result)=*first;
}
return ++result;
}
3.4 賦值fill
fill函式可以可以向容器當中的一定範圍能賦值,一共接受3個引數,類似於memset函式。
fill(beg, end, val)
4. Stirng常用操作
4.1 通過下標操作字串:
//交換當前字串與s2的值
void swap(string &s2);
//刪除pos開始的n個字元,返回修改後的字串
string &erase(int pos = 0, int n = npos);
//從pos開始查詢字元c在當前字串的位置
int find(char c, int pos = 0) const;
//從pos開始查詢字串s在當前串中的位置
int find(const char *s, int pos = 0) const;
//刪除從p0開始的n0個字元,然後在p0處插入串s
string &replace(int p0, int n0,const char *s);
//刪除從p0開始的n0個字元,然後在p0處插入串s
string &replace(int p0, int n0,const string &s);
string &insert(int p0, const char *s);
string &insert(int p0, const char *s, int n);
string &insert(int p0,const string &s);
一個示例
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "asdfghjklsdsdfgh";
cout<<s.size()<<endl;
cout<<s.find('s')<<endl;
cout<<s.find('s',s.find('s')+1)<<endl;
//將"sd"替換成"sb"
int i = 0;
while(i < s.size()){
int pos = s.find("sd",i);
if(pos == string::npos) break;
s.replace(pos,2,"mb");
cout<<s<<endl;
i = pos + 2;
}
string s2 = s;
s2.erase(0,3);
cout<<s2<<" end"<<endl;
}
4.2 通過迭代器操作字串
//刪除[first,last)之間的所有字元,返回刪除後迭代器的位置
iterator erase(iterator first, iterator last);
//刪除it指向的字元,返回刪除後迭代器的位置
iterator erase(iterator it);
5. 深度探索vector
5.1 insert的實現
在插入元素之前,需要判斷vector的備用空間大小是否大於插入元素個數,如果足夠則在原序列進行插入操作;如果不夠,則需要重新申請記憶體,將原資料和新增資料移動到新記憶體中(先是原資料插入點之前的資料移動到新記憶體中,然後是待插入資料,最後移動插入點之後的資料),然後析構元記憶體中的物件,最後再釋放原記憶體。
////////////////////////////////////////////////////////////////////////////////
// 在指定位置插入n個元素
////////////////////////////////////////////////////////////////////////////////
// insert(iterator position, size_type n, const T& x)
// |
// |---------------- 插入元素個數是否為0?
// ↓
// -----------------------------------------
// No | | Yes
// | |
// | ↓
// | return;
// |----------- 記憶體是否足夠?
// |
// -------------------------------------------------
// Yes | | No
// | |
// |------ (finish - position) > n? |
// | 分別調整指標 |
// ↓ |
// ---------------------------- |
// No | | Yes |
// | | |
// ↓ ↓ |
// 插入操作, 調整指標 插入操作, 調整指標 |
// ↓
// data_allocator::allocate(len);
// new_finish = uninitialized_copy(start, position, new_start);
// new_finish = uninitialized_fill_n(new_finish, n, x);
// new_finish = uninitialized_copy(position, finish, new_finish);
// destroy(start, finish);
// deallocate();
////////////////////////////////////////////////////////////////////////////////
template <class T, class Alloc>
void insert(iterator position, size_type n, const T& x)
{
// 如果n為0則不進行任何操作
if (n != 0)
{
if (size_type(end_of_storage - finish) >= n)
{ // 剩下的備用空間大於等於“新增元素的個數”
T x_copy = x;
// 以下計算插入點之後的現有元素個數
const size_type elems_after = finish - position;
iterator old_finish = finish;
if (elems_after > n)
{
// 插入點之後的現有元素個數 大於 新增元素個數
uninitialized_copy(finish - n, finish, finish);
finish += n; // 將vector 尾端標記後移
copy_backward(position, old_finish - n, old_finish);
fill(position, position + n, x_copy); // 從插入點開始填入新值
}
else
{
// 插入點之後的現有元素個數 小於等於 新增元素個數
uninitialized_fill_n(finish, n - elems_after, x_copy);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
fill(position, old_finish, x_copy);
}
}
else
{ // 剩下的備用空間小於“新增元素個數”(那就必須配置額外的記憶體)
// 首先決定新長度:就長度的兩倍 , 或舊長度+新增元素個數
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);
// 以下配置新的vector空間
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY
{
// 以下首先將舊的vector的插入點之前的元素複製到新空間
new_finish = uninitialized_copy(start, position, new_start);
// 以下再將新增元素(初值皆為n)填入新空間
new_finish = uninitialized_fill_n(new_finish, n, x);
// 以下再將舊vector的插入點之後的元素複製到新空間
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...)
{
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(start, finish);
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}
相關文章
- 跟我學C++中級篇——STL的學習C++
- C++ 學習筆記之——STL 庫 queueC++筆記
- C++學習筆記 — STL標準模板庫C++筆記
- C++ 學習筆記(1):STL、Vector 與 SetC++筆記
- 【演算法學習】STL庫 大小根堆的用法演算法
- C++STL學習第一篇(什麼是STL以及string的各種功能用法)C++
- stl 和 數學slide 筆記 by JeefyIDE筆記
- STL
- Stack (stl)
- 簡單STL
- STL————deque容器
- STL and Design Pattern
- C++STLC++
- STL容器---Vector
- C++STL之Vector向量詳解,用法和例子 一起學習 一起加油C++
- stl__使用篇
- STL使用篇__vector
- STL使用篇__list
- STL使用篇__deque
- STL使用篇__map
- STL使用篇__set
- STL使用篇__multimap
- STL使用篇__multiset
- C++ STL -- vectorC++
- C++ STL -- listC++
- C++ STL -- HashTableC++
- 4.2、STL初識
- STL常用序列容器
- c++stl notesC++
- C++ STL stackC++
- STL---vector(向量)
- SGI STL值List
- STL容器之deque
- STL使用篇__容器
- STL使用篇__bitset
- C++ STL listC++
- STL_string容器
- [CPP] STL 簡介