泛型算法的關鍵概念:泛型算法本身不會執行容器的操作,它們只會運行於迭代器之上,執行迭代器的操作。泛型算法運行於迭代器之上而不會執行容器操作的特性帶來了一個令人驚訝但非常必要的編程假定:算法永遠不會改變底層容器的大小。算法可能改變容器中保存的元素的值,也可能在容器移動元素,但永遠不會直接添加或刪除元素。
1.初始泛型算法
1.1 只讀算法
A.accumulate函數
頭文件:numberic ; 目的:求和;它的三個參數:前兩個求和元素的范圍,第三個是參數和的初始值;
例子:
vector
int sum=accumulate(vec.begin(),vec.end(),0);// 求vec容器中元素和;初始值為0;
string sum1=accumulate(v.begin(),v.end(),string()); //把vector容器中的string元素都連接起來;
注意:第三個參量的類型決定了函數使用哪個加法運算符以及返回值的類型。
B. equal函數
目的:用於確定兩個序列是否保存相同的值。它將第一個序列中的每個元素與第二個序列中的元素進行比較。它的三個參數:前兩個表示第一個序列的元素范圍,第三個表示第二個序列的首元素。
例子:
equal(roster1.cbegin(),roster1.cend(),roster2.cbegin()); //roster1可以是vector
1.2 寫容器的元素算法
A. fill_n函數
目的:指定的迭代器元素范圍內,進行賦值;它的三個參數:一個單迭代器、一個計數值和一個值。
例子:
vector
fill_n(vec.begin(),v.end(),0); //將所有元素重置為0;
fill_n(vec.begin(),10,0); //由於vector容器中沒有元素,這條語句的結果是未定義的。
B.back_inserter函數
頭文件:iterator ;目的:接受一個指向容器的引用,返回一個與該容器綁定的插入迭代器。當我們通過這個迭代器賦值時,會調用push_back將一個給定的值插入容器中。
C.拷貝算法
目的:是另一個向目的位置迭代器指向的輸出序列中元素寫入數據的算法。它的三個迭代器:前兩個表示一個輸入范圍,第三個表示目的序列的起始位置。
D.replace函數
目的:將容器中的給定元素用新元素替換;它的四個參數:前兩個是迭代器,第三個表示搜素的值(被替換),第四個是新值(替換的值);
例子:
replace(ilist.begin(),ilst.end(),0,42); //將序列中所有值為了0的元素都改為42;
1.3 重排容器元素的算法
A.sort函數
目的:按字典順序排序;它的參數:至少需要前後兩個迭代器的范圍;
B.unique函數
目的:排列在范圍的前部,返回指向不重復區域之後一個位置的迭代器。將相鄰的重復項都刪除,並返回一個指向不重復值的范圍末尾的迭代器。
例子:
#include
#include
#include
using namespace std;
void elimDups(vector
{
sort(word.begin(),word.end()); //按字典順序排序word,以便查找重復單詞;
for(auto k:word) //打印字母排序的word;
cout<
word.erase(end_unique,word.end()); //刪除重復的單詞;
}
int main()
{
vector
fill_n(back_inserter(vec),10,0); //插入迭代器back_inserter,回調用push_back;
fill_n(vec.begin(),vec.size(),1); //fill_n(dest,n,val):接受一個迭代器、計數值、一個值;容器賦值語句;
for(auto c: vec)
cout<
int a2[sizeof(a1)/sizeof(*a1)]; //保存a1與a2數組大小相同;
auto ret=copy(begin(a1),end(a1),a2) ;//把a1的內容拷貝給a2;
for(auto b:a2)
cout< vector
elimDups(vec1);
for(auto k:vec1)
cout<
}
顯示結果:
2.定制操作
A.謂詞
謂詞是一個可調用的表達式,其返回結果是一個能用作條件的值。謂詞分為:一元謂詞和二元謂詞。幾元謂詞接受幾元參數;
B.lambda函數
可調用對象定義;對於一個對象或一個表達式,如果可以對其使用調用運算符,則稱為可調用的;可調用的對象有:函數、函數指針、重載函數調用運算符的類和lambda表達式。
lambda表達式形式:
[capture list](parameter list)->return type{function body};
capture list是一個lambda所在函數中定義的局部變量的列表(通常為空);
return type、parameter list和function body分別表示返回類型、參數列表和函數體。
調用find_if:查找第一個長度大於等於sz的元素;
auto wc=find_if(words.begin(),words.end(),[sz](const string &a){return a.size()>=sz;});
C.for_each算法
該算法接受一個可調用對象,並對輸入序列中每個元素調用此對象:
for_each(wc,words.end(),[](const string &s){cout<
cout<
注意:為了指示編譯器推斷捕獲列表,應在捕獲列表中寫一個&或=;&告訴編譯器采用引用方式,=則表示采用值捕獲方式。
3.參數綁定
標准庫bind函數
頭文件:functional ;它接受一個可調用對象,生成一個新的可調用對象來適應原對象的參數列表。
調用bind的形式:
auto newCallable=bind(callable, arg_list);
newCallable本身是一個可調用對象,arg_list是一個逗號分隔的參數列表,對應給定的callable的參數。arg_list中的參數可能包含形如_n的名字,_1是newCallable的第一個參數,_2為第二個參數,依次類推。
4.再探迭代器
迭代器有:插入迭代器、流迭代器、反向迭代器、移動迭代器;
4.1插入迭代器
插入器:是一種迭代器適配器,它接受一個容器,生成一個迭代器,能實現向給定容器添加元素。
插入迭代器三種類型:back_inserter(調用push_back)、front_inserter(調用push_front)和inserter(插入到迭代器某個指定位置的前面);這些插入迭代器前面章節都做了詳細介紹;
4.2 iostream迭代器
有兩類:istream_iterator讀取輸入流、ostream_iterator向一個輸出流寫數據。
istream_iterator
istream_iterator
ostream_iterator
ostream_iterator
4.3反向迭代器
反向迭代器:就是從尾元素向首元素反向移動的迭代器。知道迭代器,從而想想只是方向顛倒,就能更好的去理解反向迭代器。
反向迭代器的目的:表示元素范圍,而這些范圍是不對稱的,這導致一個重要的結果:當我們從一個普通迭代器初始化一個反向迭代器,或是給一個反向迭代器賦值時,結果迭代器與原迭代器指向並不是相同的元素。
5.泛型算法結構
算法操作的五個迭代器:輸入迭代器、輸出迭代器、前向迭代器、雙向迭代器和隨機訪問迭代器。
輸入迭代器:只讀,不寫;單遍掃描,只能遞增;
輸出迭代器:只寫,不讀;單遍掃描,只能遞增;
前向迭代器:可讀寫;多遍掃描,只能遞增;
雙向迭代器:可讀寫;多遍掃描,可遞增遞減;
隨機訪問迭代器:可讀寫;多遍掃描,支持全部迭代器運算
總結C++11特性:
1.lambda表達式
本章上面有重點講解,並有運用的形式;我們可以將它理解為一個為命名的內聯函數。
2.lambda尾置返回類型
例子:
transform(vi.begin(),vi.end(),vi.begin(),[](int i)->int{if(i<0) return -i;else return i;});
傳遞給transform的第四個參數是一個lambda,它的捕獲列表是空的,接受單一int參數,返回一個int值。它的函數體是一個返回其參數的絕對值的if語句。
3.bind函數
本章上面對bind函數做了講解,我們記住_n的參數理解,就能夠運用它。