C++STL入門筆記
C++ STL中最基本以及最常用的類或容器無非就是以下幾個:
- string
- vector
- set
- list
- map
首先看看我們C語言一般怎麼使用字串的
char* s1 = "Hello SYSU!"; //建立指標指向字串常量,這段字串我們是不能修改的
//想要建立 可以修改的字串,我們可以使用陣列分配空間
char s2[20] = "Hello SYSU!";
//或者這樣
char s3[] = "Hello SYSU!";
//當然我們也可以動態分配記憶體
char* s4 = (char*)malloc(20);
gets(s4);
C++ 標準庫中的string表示可變長的字串,它在標頭檔案string裡面。
#include <string>
用string初始化字串分兩類:用“=”號就是拷貝初始化,否則就是直接初始化。
string s1;//初始化字串,空字串
string s2 = s1; //拷貝初始化,深拷貝字串
string s3 = "I am Yasuo"; //直接初始化,s3存了字串
string s4(10, 'a'); //s4存的字串是aaaaaaaaaa
string s5(s4); //拷貝初始化,深拷貝字串
string s6("I am Ali"); //直接初始化
string s7 = string(6, 'c'); //拷貝初始化,cccccc
#include <iostream> #include <string> using namespace std; int main() { string s1;//初始化字串,空字串 string s2 = s1; //拷貝初始化,深拷貝字串 string s3 = "I am Yasuo"; //直接初始化,s3存了字串 string s4(10, 'a'); //s4存的字串是aaaaaaaaaa string s5(s4); //拷貝初始化,深拷貝字串 string s6("I am Ali"); //直接初始化 string s7 = string(6, 'c'); //拷貝初始化,cccccc //string的各種操作 string s8 = s3 + s6;//將兩個字串合併成一個 s3 = s6;//用一個字串來替代另一個字串的對用元素 cin >> s1; cout << s1 << endl; cout << s2 << endl; cout << s3 << endl; cout << s4 << endl; cout << s5 << endl; cout << s6 << endl; cout << s7 << endl; cout << s8 << endl; cout << "s7 size = " << s7.size() << endl; //字串長度,不包括結束符 cout << (s2.empty() ? "This string is empty" : "This string is not empty") << endl;; system("pause"); return 0; }
string的IO操作
使用cin讀入字串時,遇到空白就停止讀取。比如程式輸入的是
" Hello World"
那麼我們得到的字串將是"Hello",前面的空白沒了,後面的world也讀不出來。
如果我們想把整個hello world讀進來怎麼辦?那就這樣做
cin>>s1>>s2;
hello存在s1裡,world存在s2裡了。
有時我們想把一個句子存下來,又不想像上面那樣建立多個string來儲存單詞,怎麼辦?
那就是用getline來獲取一整行內容。
string str; getline(cin, str); cout << str << endl;
當把string物件和字元面值及字串面值混在一條語句中使用時,必須確保+的兩側的運算物件至少有一個是string
string s1 = s2 + ", "; //正確
string s3 = "s " + ", "; //錯誤
string s4 = "hello" + ", " + s1; //錯誤
string s5 = s1 + "hello " + ", "; //改一下順序,s1放前頭,正確了,注意理解=號右邊的運算順序
處理string中的字元
訪問字串的每個字元
for (int i = 0; i < s3.size(); i++)
{
cout << s3[i] << endl;
s3[i] = 's';
}
在C語言中我都是用下標或者指標來訪問陣列元素,而在C++裡,有個新奇的東西叫做迭代器iterator,我們可以使用它來訪問容器元素。
string str("hi sysu");
for (string::iterator it = str.begin(); it != str.end(); it++)
{
cout << *it << endl;
}
我們也可以是使用const_iterator使得訪問元素時是能讀不能寫,這跟常量指標意思差不多。
string str2("hi sysu");
for (string::const_iterator it = str2.begin(); it != str2.end(); it++)
{
cout << *it << endl;
*it = 'l'; //這是錯誤的,不能寫
}
string還有一些很好用的函式,比如找子串
string sq("heoolo sdaa ss");
cout << s.find("aa", 0) << endl; //返回的是子串位置。第二個引數是查詢的起始位置,如果找不到,就返回string::npos
if (s.find("aa1", 0) == string::npos)
{
cout << "找不到該子串!" << endl;
}
vector
C++ STL中的verctor好比是C語言中的陣列,但是vector又具有陣列沒有的一些高階功能。與陣列相比,vector就是一個可以不用再初始化就必須制定大小的邊長陣列,當然了,它還有許多高階功能。
要想用vector首先得包含標頭檔案vector。
#include <vector>
怎麼初始化?
如果vector的元素型別是int,預設初始化為0;如果vector元素型別為string,則預設初始化為空字串。
vector<int> v1;
vector<father> v2;
vector<string> v3;
vector<vector<int> >; //注意空格。這裡相當於二維陣列int a[n][n];
vector<int> v5 = { 1,2,3,4,5 }; //列表初始化,注意使用的是花括號
vector<string> v6 = { "hi","my","name","is","lee" };
vector<int> v7(5, -1); //初始化為-1,-1,-1,-1,-1。第一個引數是數目,第二個引數是要初始化的值
vector<string> v8(3, "hi");
vector<int> v9(10); //預設初始化為0
vector<int> v10(4); //預設初始化為空字串
如何向vector新增元素?
請使用push_back加入元素,並且這個元素是被加在陣列尾部的。
for (int i = 0; i < 20; i++)
{
v1.push_back(i);
}
vector其他的操作
訪問和操作vector中的每個元素
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << endl;
v1[i] = 100;
cout << v1[i] << endl;
}
注意:只能對已存在的元素進行賦值或者修改操作,如果是要加入新元素,務必使用push_back。push_back的作用有兩個:告訴編譯器為新元素開闢空間、將新元素存入新空間裡。
比如下面的程式碼是錯誤的,但是編譯器不會報錯,就像是陣列越界。
vector<int> vec;
vec[0] = 1; //錯誤!
當然我們也可以選擇使用迭代器來訪問元素
vector<string> v6 = { "hi","my","name","is","lee" };
for (vector<string>::iterator iter = v6.begin(); iter != v6.end(); iter++)
{
cout << *iter << endl;
//下面兩種方法都行
cout << (*iter).empty() << endl;
cout << iter->empty() << endl;
}
上面是正向迭代,如果我們想從後往前迭代該如何操作?
使用反向迭代器
for (vector<string>::reverse_iterator iter = v6.rbegin(); iter != v6.rend(); iter++)
{
cout << *iter << endl;
}
vector最常用的增刪操作
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <typename T>
void showvector(vector<T> v)
{
for (vector<T>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main()
{
vector<string> v6 = { "hi","my","name","is","lee" };
v6.resize(3); //重新調整vector容量大小
showvector(v6);
vector<int> v5 = { 1,2,3,4,5 }; //列表初始化,注意使用的是花括號
cout << v5.front() << endl; //訪問第一個元素
cout << v5.back() << endl; //訪問最後一個元素
showvector(v5);
v5.pop_back(); //刪除最後一個元素
showvector(v5);
v5.push_back(6); //加入一個元素並把它放在最後
showvector(v5);
v5.insert(v5.begin()+1,9); //在第二個位置插入新元素
showvector(v5);
v5.erase(v5.begin() + 3); //刪除第四個元素
showvector(v5);
v5.insert(v5.begin() + 1, 7,8); //連續插入7個8
showvector(v5);
v5.clear(); //清除所有內容
showvector(v5);
system("pause");
return 0;
}
注意:雖然vertor物件可以動態增長,但是也或有一點副作用:已知的一個限制就是不能再範圍for迴圈中向vector物件新增元素。另外一個限制就是任何一種可能改變vector物件容量的操作,不如push_back,都會使該迭代器失效。
總而言之就是:但凡使用了迭代器的迴圈體,都不要向迭代器所屬的容器新增元素!
C++中push_back和insert兩個有什麼區別?
顧名思義push_back把元素插入容器末尾,insert把元素插入任何你指定的位置。
不過push_back速度一般比insert快。如果能用push_back儘量先用push_back。
set
set跟vector差不多,它跟vector的唯一區別就是,set裡面的元素是有序的且唯一的,只要你往set裡新增元素,它就會自動排序,而且,如果你新增的元素set裡面本來就存在,那麼這次新增操作就不執行。要想用set先加個標頭檔案set。
#include <set>
#include <iostream>
#include <set>
#include <string>
using namespace std;
template <typename T>
void showset(set<T> v)
{
for (set<T>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main()
{
set<int> s1{9,8,1,2,3,4,5,5,5,6,7,7 }; //自動排序,從小到大,剔除相同項
showset(s1);
set<string> s2{ "hello","sysy","school","hello" }; //字典序排序
showset(s2);
s1.insert(9); //有這個值了,do nothing
showset(s1);
s2.insert("aaa"); //沒有這個字串,新增並且排序
showset(s2);
system("pause");
return 0;
}
list
list就是連結串列,在C語言中我們想使用連結串列都是自己去實現的,實現起來倒不難,但是如果有現成的高效的連結串列可以使用的話,我們就不需要重複造輪子了。STL就提供了list容器給我們。
list是一個雙向連結串列,而單鏈表對應的容器則是foward_list。
list即雙向連結串列的優點是插入和刪除元素都比較快捷,缺點是不能隨機訪問元素。
初始化方式就大同小異了,跟vector基本一樣。要想用list先加個標頭檔案list。
#include <list>
#include <iostream>
#include <list>
#include <string>
using namespace std;
template <typename T>
void showlist(list<T> v)
{
for (list<T>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it;
}
cout << endl;
}
int main()
{
list<int> l1{ 1,2,3,4,5,5,6,7,7 };
showlist(l1);
list<double> l2;
list<char> l3(10);
list<int> l4(5, 10); //將元素都初始化為10
showlist(l4);
system("pause");
return 0;
}
值得注意的是,list容器不能呼叫algorithm下的sort函式進行排序,因為sort函式要求容器必須可以隨機儲存,而list做不到。所以,list自己做了一個自己用的排序函式,用法如下:
list<int> l1{ 8,5,7,6,1,2,3,4,5,5,6,7,7 };
l1.sort();
map
map運用了雜湊表地址對映的思想,也就是key-value的思想,來實現的。
首先給出map最好用也最最常用的用法例子,就是用字串作為key去查詢操作對應的value。
要使用map得先加個標頭檔案map。
#include <map>
#include <iostream>
#include <map>
#include <string>
using namespace std;
void showmap(map<string, int> v)
{
for (map<string, int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << it->first << " " << it->second << endl; //注意用法,不是用*it來訪問了。first表示的是key,second存的是value
}
cout << endl;
}
int main()
{
map<string, int> m1; //<>裡的第一個引數表示key的型別,第二個引數表示value的型別
m1["Kobe"] = 100;
m1["James"] = 99;
m1["Curry"] = 98;
string s("Jordan");
m1[s] = 90;
cout << m1["Kobe"] << endl;
cout << m1["Jordan"] << endl;
cout << m1["Durant"] << endl; //不存在這個key,就顯示0
m1.erase("Curry");//通過關鍵字來刪除
showmap(m1);
m1.insert(pair<string, int>("Harris", 89)); //也可以通過insert函式來實現增加元素
showmap(m1);
m1.clear(); //清空全部
system("pause");
return 0;
}
如果想看看某個存不存在某個key,可以用count來判斷
if (m1.count("Lee"))
{
cout << "Lee is in m1!" << endl;
}
else
{
cout << "Lee do not exist!" << endl;
}
用迭代器來訪問元素
for (map<string, int>::iterator it = m1.begin(); it != m1.end(); it++)
{
cout << it->first<<" "<<it->second << endl; //注意用法,不是用*it來訪問了。first表示的是key,second存的是value
}
一、一般介紹
STL(Standard Template Library),即標準模板庫,是一個具有工業強度的,高效的C++程式庫。它被容納於C++標準程式庫(C++ Standard Library)中,是ANSI/ISO C++標準中最新的也是極具革命性的一部分。該庫包含了諸多在電腦科學領域裡所常用的基本資料結構和基本演算法。為廣大C++程式設計師們提供了一個可擴充套件的應用框架,高度體現了軟體的可複用性。
從邏輯層次來看,在STL中體現了泛型化程式設計的思想(generic programming),引入了諸多新的名詞,比如像需求(requirements),概念(concept),模型(model),容器(container),演算法(algorithmn),迭代子(iterator)等。與OOP(object-oriented programming)中的多型(polymorphism)一樣,泛型也是一種軟體的複用技術;
從實現層次看,整個STL是以一種型別引數化(type parameterized)的方式實現的,這種方式基於一個在早先C++標準中沒有出現的語言特性--模板(template)。如果查閱任何一個版本的STL原始碼,你就會發現,模板作為構成整個STL的基石是一件千真萬確的事情。除此之外,還有許多C++的新特性為STL的實現提供了方便;
二、STL的六大元件
- 容器(Container),是一種資料結構,如list,vector,和deques ,以模板類的方法提供。為了訪問容器中的資料,可以使用由容器類輸出的迭代器;
- 迭代器(Iterator),提供了訪問容器中物件的方法。例如,可以使用一對迭代器指定list或vector中的一定範圍的物件。迭代器就如同一個指標。事實上,C++的指標也是一種迭代器。但是,迭代器也可以是那些定義了operator*()以及其他類似於指標的操作符地方法的類物件;
- 演算法(Algorithm),是用來操作容器中的資料的模板函式。例如,STL用sort()來對一個vector中的資料進行排序,用find()來搜尋一個list中的物件,函式本身與他們操作的資料的結構和型別無關,因此他們可以在從簡單陣列到高度複雜容器的任何資料結構上使用;
- 仿函式(Function object,仿函式(functor)又稱之為函式物件(function object),其實就是過載了()操作符的struct,沒有什麼特別的地方
- 迭代介面卡(Adaptor)
- 空間配製器(allocator)其中主要工作包括兩部分1.物件的建立與銷燬 2.記憶體的獲取與釋放
以下主要討論:容器,迭代器,演算法,介面卡。如欲詳加了解 參見C++ Primer
1.STL容器
1)序列式容器(Sequence containers),每個元素都有固定位置--取決於插入時機和地點,和元素值無關,vector、deque、list;
Vectors:將元素置於一個動態陣列中加以管理,可以隨機存取元素(用索引直接存取),陣列尾部新增或移除元素非常快速。但是在中部或頭部安插元素比較費時;
Deques:是“double-ended queue”的縮寫,可以隨機存取元素(用索引直接存取),陣列頭部和尾部新增或移除元素都非常快速。但是在中部或頭部安插元素比較費時;
Lists:雙向連結串列,不提供隨機存取(按順序走到需存取的元素,O(n)),在任何位置上執行插入或刪除動作都非常迅速,內部只需調整一下指標;
2)關聯式容器(Associated containers),元素位置取決於特定的排序準則,和插入順序無關,set、multiset、map、multimap;
Sets/Multisets:內部的元素依據其值自動排序,Set內的相同數值的元素只能出現一次,Multisets內可包含多個數值相同的元素,內部由二叉樹實現(實際上基於紅黑樹(RB-tree)實現),便於查詢;
Maps/Multimaps:Map的元素是成對的鍵值/實值,內部的元素依據其值自動排序,Map內的相同數值的元素只能出現一次,Multimaps內可包含多個數值相同的元素,內部由二叉樹實現(實際上基於紅黑樹(RB-tree)實現),便於查詢;
另外有其他容器hash_map,hash_set,hash_multiset,hash_multimap。
容器的比較:
Vector | Deque | List | Set | MultiSet | Map | MultiMap | |
內部結構 | dynamic array | array of arrays | double linked list | binary tree | binary tree | binary tree | binary tree |
隨機存取 | Yes | Yes | No | No | No | Yes(key) | No |
搜尋速度 | 慢 | 慢 | 很慢 | 快 | 快 | 快 | 快 |
快速插入移除 | 尾部 | 首尾 | 任何位置 | -- | -- | -- | -- |
2.STL迭代器
Iterator(迭代器)模式又稱Cursor(遊標)模式,用於提供一種方法順序訪問一個聚合物件中各個元素,
而又不需暴露該物件的內部表示。或者這樣說可能更容易理解:Iterator模式是運用於聚合物件的一種模式,通過運用該模式,使得我們可以在不知道物件內部表示的情況下,按照一定順序(由iterator提供的方法)訪問聚合物件中的各個元素。
迭代器的作用:能夠讓迭代器與演算法不干擾的相互發展,最後又能無間隙的粘合起來,過載了*,++,==,!=,=運算子。用以操作複雜的資料結構,容器提供迭代器,演算法使用迭代器;
常見的一些迭代器型別:iterator、const_iterator、reverse_iterator和const_reverse_iterator
迭代器一般宣告使用示例
vector<T>::iterator it; list<T>::iterator it; deque<T>::iterator it;
input output
\ /
forward
|
bidirectional
|
random access
要注意,上面這圖表並不是表明它們之間的繼承關係:而只是描述了迭代器的種類和介面。處於圖表下層的迭代器都是相對於處於圖表上層迭代器的擴張集。例如:forward迭代器不但擁有input和output迭代器的所有功能,還擁有更多的功能。
各個迭代器的功能如下:
迭代器類別 |
說明 |
輸入 |
從容器中讀取元素。輸入迭代器只能一次讀入一個元素向前移動,輸入迭代器只支援一遍演算法,同一個輸入迭代器不能兩遍遍歷一個序列 |
輸出 |
向容器中寫入元素。輸出迭代器只能一次一個元素向前移動。輸出迭代器只支援一遍演算法,統一輸出迭代器不能兩次遍歷一個序列 |
正向 |
組合輸入迭代器和輸出迭代器的功能,並保留在容器中的位置 |
雙向 |
組合正向迭代器和逆向迭代器的功能,支援多遍演算法 |
隨機訪問 |
組合雙向迭代器的功能與直接訪問容器中任何元素的功能,即可向前向後跳過任意個元素 |
迭代器的操作:
每種迭代器均可進行包括表中前一種迭代器可進行的操作。
迭代器操作 |
說明 |
所有迭代器 |
|
p++ |
後置自增迭代器 |
++p |
前置自增迭代器 |
輸入迭代器 |
|
*p |
復引用迭代器,作為右值 |
p=p1 |
將一個迭代器賦給另一個迭代器 |
p==p1 |
比較迭代器的相等性 |
p!=p1 |
比較迭代器的不等性 |
輸出迭代器 |
|
*p |
復引用迭代器,作為左值 |
p=p1 |
將一個迭代器賦給另一個迭代器 |
正向迭代器 |
提供輸入輸出迭代器的所有功能 |
雙向迭代器 |
|
--p |
前置自減迭代器 |
p-- |
後置自減迭代器 |
隨機迭代器 |
|
p+=i |
將迭代器遞增i位 |
p-=i |
將迭代器遞減i位 |
p+i |
在p位加i位後的迭代器 |
p-i |
在p位減i位後的迭代器 |
p[i] |
返回p位元素偏離i位的元素引用 |
p<p1 |
如果迭代器p的位置在p1前,返回true,否則返回false |
p<=p1 |
p的位置在p1的前面或同一位置時返回true,否則返回false |
p>p1 |
如果迭代器p的位置在p1後,返回true,否則返回false |
p>=p1 |
p的位置在p1的後面或同一位置時返回true,否則返回false |
只有順序容器和關聯容器支援迭代器遍歷,各容器支援的迭代器的類別如下:
容器 |
支援的迭代器類別 |
說明 |
vector |
隨機訪問 |
一種隨機訪問的陣列型別,提供了對陣列元素進行快速隨機訪問以及在序列尾部進行快速的插入和刪除操作的功能。可以再需要的時候修改其自身的大小 |
deque |
隨機訪問 |
一種隨機訪問的陣列型別,提供了序列兩端快速進行插入和刪除操作的功能。可以再需要的時候修改其自身的大小 |
list |
雙向 |
一種不支援隨機訪問的陣列型別,插入和刪除所花費的時間是固定的,與位置無關。 |
set |
雙向 |
一種隨機存取的容器,其關鍵字和資料元素是同一個值。所有元素都必須具有惟一值。 |
multiset |
雙向 |
一種隨機存取的容器,其關鍵字和資料元素是同一個值。可以包含重複的元素。 |
map |
雙向 |
一種包含成對數值的容器,一個值是實際資料值,另一個是用來尋找資料的關鍵字。一個特定的關鍵字只能與一個元素關聯。 |
multimap |
雙向 |
一種包含成對數值的容器,一個值是實際資料值,另一個是用來尋找資料的關鍵字。一個關鍵字可以與多個數據元素關聯。 |
stack |
不支援 |
介面卡容器型別,用vector,deque或list物件建立了一個先進後出容器 |
queue |
不支援 |
介面卡容器型別,用deque或list物件建立了一個先進先出容器 |
priority_queue |
不支援 |
介面卡容器型別,用vector或deque物件建立了一個排序佇列 |
3.STL演算法
STL演算法部分主要由標頭檔案<algorithm>,<numeric>,<functional>組成。要使用 STL中的演算法函式必須包含標頭檔案<algorithm>,對於數值演算法須包含<numeric>,<functional>中則定義了一些模板類,用來宣告函式物件。
STL中演算法大致分為四類:
1)、非可變序列演算法:指不直接修改其所操作的容器內容的演算法。
2)、可變序列演算法:指可以修改它們所操作的容器內容的演算法。
3)、排序演算法:包括對序列進行排序和合並的演算法、搜尋演算法以及有序序列上的集合操作。
4)、數值演算法:對容器內容進行數值計算。
以下對所有演算法進行細緻分類並標明功能:
<一>查詢演算法(13個):判斷容器中是否包含某個值
adjacent_find: 在iterator對標識元素範圍內,查詢一對相鄰重複元素,找到則返回指向這對元素的第一個元素的ForwardIterator。否則返回last。過載版本使用輸入的二元操作符代替相等的判斷。
binary_search: 在有序序列中查詢value,找到返回true。過載的版本實用指定的比較函式物件或函式指標來判斷相等。
count: 利用等於操作符,把標誌範圍內的元素與輸入值比較,返回相等元素個數。
count_if: 利用輸入的操作符,對標誌範圍內的元素進行操作,返回結果為true的個數。
equal_range: 功能類似equal,返回一對iterator,第一個表示lower_bound,第二個表示upper_bound。
find: 利用底層元素的等於操作符,對指定範圍內的元素與輸入值進行比較。當匹配時,結束搜尋,返回該元素的一個InputIterator。
find_end: 在指定範圍內查詢"由輸入的另外一對iterator標誌的第二個序列"的最後一次出現。找到則返回最後一對的第一個ForwardIterator,否則返回輸入的"另外一對"的第一個ForwardIterator。過載版本使用使用者輸入的操作符代替等於操作。
find_first_of: 在指定範圍內查詢"由輸入的另外一對iterator標誌的第二個序列"中任意一個元素的第一次出現。過載版本中使用了使用者自定義操作符。
find_if: 使用輸入的函式代替等於操作符執行find。
lower_bound: 返回一個ForwardIterator,指向在有序序列範圍內的可以��入指定值而不破壞容器順序的第一個位置。過載函式使用自定義比較操作。
upper_bound: 返回一個ForwardIterator,指向在有序序列範圍內插入value而不破壞容器順序的最後一個位置,該位置標誌一個大於value的值。過載函式使用自定義比較操作。
search: 給出兩個範圍,返回一個ForwardIterator,查詢成功指向第一個範圍內第一次出現子序列(第二個範圍)的位置,查詢失敗指向last1。過載版本使用自定義的比較操作。
search_n: 在指定範圍內查詢val出現n次的子序列。過載版本使用自定義的比較操作。
<二>排序和通用演算法(14個):提供元素排序策略
inplace_merge: 合併兩個有序序列,結果序列覆蓋兩端範圍。過載版本使用輸入的操作進行排序。
merge: 合併兩個有序序列,存放到另一個序列。過載版本使用自定義的比較。
nth_element: 將範圍內的序列重新排序,使所有小於第n個元素的元素都出現在它前面,而大於它的都出現在後面。過載版本使用自定義的比較操作。
partial_sort: 對序列做部分排序,被排序元素個數正好可以被放到範圍內。過載版本使用自定義的比較操作。
partial_sort_copy: 與partial_sort類似,不過將經過排序的序列複製到另一個容器。
partition: 對指定範圍內元素重新排序,使用輸入的函式,把結果為true的元素放在結果為false的元素之前。
random_shuffle: 對指定範圍內的元素隨機調整次序。過載版本輸入一個隨機數產生操作。
reverse: 將指定範圍內元素重新反序排序。
reverse_copy: 與reverse類似,不過將結果寫入另一個容器。
rotate: 將指定範圍內元素移到容器末尾,由middle指向的元素成為容器第一個元素。
rotate_copy: 與rotate類似,不過將結果寫入另一個容器。
sort: 以升序重新排列指定範圍內的元素。過載版本使用自定義的比較操作。
stable_sort: 與sort類似,不過保留相等元素之間的順序關係。
stable_partition: 與partition類似,不過不保證保留容器中的相對順序。
<三>刪除和替換演算法(15個)
copy: 複製序列
copy_backward: 與copy相同,不過元素是以相反順序被拷貝。
iter_swap: 交換兩個ForwardIterator的值。
remove: 刪除指定範圍內所有等於指定元素的元素。注意,該函式不是真正刪除函式。內建函式不適合使用remove和remove_if函式。
remove_copy: 將所有不匹配元素複製到一個制定容器,返回OutputIterator指向被拷貝的末元素的下一個位置。
remove_if: 刪除指定範圍內輸入操作結果為true的所有元素。
remove_copy_if: 將所有不匹配元素拷貝到一個指定容器。
replace: 將指定範圍內所有等於vold的元素都用vnew代替。
replace_copy: 與replace類似,不過將結果寫入另一個容器。
replace_if: 將指定範圍內所有操作結果為true的元素用新值代替。
replace_copy_if: 與replace_if,不過將結果寫入另一個容器。
swap: 交換儲存在兩個物件中的值。
swap_range: 將指定範圍內的元素與另一個序列元素值進行交換。
unique: 清除序列中重複元素,和remove類似,它也不能真正刪除元素。過載版本使用自定義比較操作。
unique_copy: 與unique類似,不過把結果輸出到另一個容器。
<四>排列組合演算法(2個):提供計算給定集合按一定順序的所有可能排列組合
next_permutation: 取出當前範圍內的排列,並重新排序為下一個排列。過載版本使用自定義的比較操作。
prev_permutation: 取出指定範圍內的序列並將它重新排序為上一個序列。如果不存在上一個序列則返回false。過載版本使用自定義的比較操作。
<五>算術演算法(4個)
accumulate: iterator對標識的序列段元素之和,加到一個由val指定的初始值上。過載版本不再做加法,而是傳進來的二元操作符被應用到元素上。
partial_sum: 建立一個新序列,其中每個元素值代表指定範圍內該位置前所有元素之和。過載版本使用自定義操作代替加法。
inner_product: 對兩個序列做內積(對應元素相乘,再求和)並將內積加到一個輸入的初始值上。過載版本使用使用者定義的操作。
adjacent_difference: 建立一個新序列,新序列中每個新值代表當前元素與上一個元素的差。過載版本用指定二元操作計算相鄰元素的差。
<六>生成和異變演算法(6個)
fill: 將輸入值賦給標誌範圍內的所有元素。
fill_n: 將輸入值賦給first到first+n範圍內的所有元素。
for_each: 用指定函式依次對指定範圍內所有元素進行迭代訪問,返回所指定的函式型別。該函式不得修改序列中的元素。
generate: 連續呼叫輸入的函式來填充指定的範圍。
generate_n: 與generate函式類似,填充從指定iterator開始的n個元素。
transform: 將輸入的操作作用與指定範圍內的每個元素,併產生一個新的序列。過載版本將操作作用在一對元素上,另外一個元素來自輸入的另外一個序列。結果輸出到指定容器。
<七>關係演算法(8個)
equal: 如果兩個序列在標誌範圍內元素都相等,返回true。過載版本使用輸入的操作符代替預設的等於操作符。
includes: 判斷第一個指定範圍內的所有元素是否都被第二個範圍包含,使用底層元素的<操作符,成功返回true。過載版本使用使用者輸入的函式。
lexicographical_compare: 比較兩個序列。過載版本使用使用者自定義比較操作。
max: 返回兩個元素中較大一個。過載版本使用自定義比較操作。
max_element: 返回一個ForwardIterator,指出序列中最大的元素。過載版本使用自定義比較操作。
min: 返回兩個元素中較小一個。過載版本使用自定義比較操作。
min_element: 返回一個ForwardIterator,指出序列中最小的元素。過載版本使用自定義比較操作。
mismatch: 並行比較兩個序列,指出第一個不匹配的位置,返回一對iterator,標誌第一個不匹配元素位置。如果都匹配,返回每個容器的last。過載版本使用自定義的比較操作。
<八>集合演算法(4個)
set_union: 構造一個有序序列,包含兩個序列中所有的不重複元素。過載版本使用自定義的比較操作。
set_intersection: 構造一個有序序列,其中元素在兩個序列中都存在。過載版本使用自定義的比較操作。
set_difference: 構造一個有序序列,該序列僅保留第一個序列中存在的而第二個中不存在的元素。過載版本使用自定義的比較操作。
set_symmetric_difference: 構造一個有序序列,該序列取兩個序列的對稱差集(並集-交集)。
<九>堆演算法(4個)
make_heap: 把指定範圍內的元素生成一個堆。過載版本使用自定義比較操作。
pop_heap: 並不真正把最大元素從堆中彈出,而是重新排序堆。它把first和last-1交換,然後重新生成一個堆。可使用容器的back來訪問被"彈出"的元素或者使用pop_back進行真正的刪除。過載版本使用自定義的比較操作。
push_heap: 假設first到last-1是一個有效堆,要被加入到堆的元素存放在位置last-1,重新生成堆。在指向該函式前,必須先把元素插入容器後。過載版本使用指定的比較操作。
sort_heap: 對指定範圍內的序列重新排序,它假設該序列是個有序堆。過載版本使用自定義比較操作。
4.介面卡
STL提供了三個容器介面卡:queue、priority_queue、stack。這些介面卡都是包裝了vector、list、deque中某個順序容器的包裝器。注意:介面卡沒有提供迭代器,也不能同時插入或刪除多個元素。下面對各個介面卡進行概括總結。
(1)stack用法
#include <stack> template < typename T, typename Container=deque > class stack;
可以使用三個標準順序容器vecotr、deque(預設)、list中的任何一個作為stack的底層模型。
bool stack<T>::empty() //判斷堆疊是否為空 void stack<T>::pop() //彈出棧頂資料 stack<T>::push(T x) //壓入一個數據 stack<T>::size_type stack<T>::size() //返回堆疊長度 T stack<T>::top() //得到棧頂資料
程式碼示例:
stack<int> intDequeStack; stack<int,vector<int>> intVectorStack; stack<int,list<int>> intListStack;
(2)queue用法
#include <queue> template<typename T, typename Container = deque<T> > class queue;
第一個引數指定要在queue中儲存的型別,第二個引數規定queue適配的底層容器,可供選擇的容器只有dequeue和list。對大多數用途使用預設的dequeue。
queue<T>::push(T x) void queue<T>::pop() T queue<T>::back() T queue<T>::front() queue<T>::size_type queue<T>::size() bool queue<T>::empty()
程式碼示例:
queue<int> intDequeQueue; queue<int,list<int>> intListQueue; (3)priority_queue用法
#include <queue> template <typename T, typename Container = vector<T>, typename Compare = less<T> > class priority_queue;
priority_queue也是一個佇列,其元素按有序順序排列。其不採用嚴格的FIFO順序,給定時刻位於隊頭的元素正是有最高優先順序的元素。如果兩個元素有相同的優先順序,那麼它們在佇列中的順序就遵循FIFO語義。預設適配的底層容器是vector,也可以使用deque,list不能用,因為priority_queue要求能對元素隨機訪問以便進行排序。
priority_queue<T>::push(T x) void priority_queue<T>::pop() T priority_queue<T>::top() priority_queue<T>::size_type priority_queue<T>::size() bool priority_queue<T>::empty()
程式碼示例:
priority_queue< int, vector<int>, greater<int> > priority_queue< int, list<int>, greater<int> >
標準庫預設使用元素型別的<操作符來確定它們之間的優先順序關係,用法有三:
優先佇列第一種用法,通過預設使用的<操作符可知在整數中元素大的優先順序高。
priority_queue<int> qi;
示例中輸出結果為:9 6 5 3 2
優先佇列第二種用法,建立priority_queue時傳入一個比較函式,使用functional.h函式物件作為比較函式。
priority_queue<int, vector<int>, greater<int> >qi2;
示例2中輸出結果為:2 3 5 6 9
優先佇列第三種用法,是自定義優先順序。
struct node { friend bool operator< (node n1, node n2) { return n1.priority < n2.priority; } int priority; int value; }; priority_queue<node> qn;
在示例3中輸出結果為:
優先順序 值
9 5
8 2
6 1
2 3
1 4
在該結構中,value為值,priority為優先順序。通過自定義operator<操作符來比較元素中的優先順序。注意:必須是自定義<操作符才行,把上述的結構中的<操作符改成>編譯不通過。