地點:基地
————————————————————————————————————
泛型演算法並不直接操作容器,而是遍歷兩個迭代器指定的乙個元素範圍,如此將演算法是作用容器分離,實現通用性。泛型演算法多數定義在標頭檔案algorithm中。比如我們想在vector下找到乙個特定值,可實現如下:
#include#include#includeusing namespace std;
int main();
int val = 2;
auto result = find(vec.cbegin(), vec.cend(), val);
cout << "the value" << val << (result == vec.cend() ? " is not present" : " is present") << endl;
return 0;
}
可見,我們傳遞find函式的前兩個引數描述的是查詢範圍,第三個引數是查詢目標,find將目標值在查詢範圍裡逐一比較,一相等就返回該元素的迭代器,如果一直不相等,則匹配到了最後的迭代器,find函式不得不返回該迭代器,獲得迭代器之後,我們稍微做處理,判斷這個迭代器是不是最後乙個迭代器,即end位置來決定是不是查詢成功。
正如前面所說,find迭代器操作的是迭代器,任何可提供迭代器的容器都可用fand演算法,另外,由於指標在很多地方與迭代器行為相似,因此我們還可以將find作用於陣列,找到返回對於元素指標,沒找到返回尾元素之後的指標。比如:
#include#includeusing namespace std;
int main();
int val = 8;
auto result = find(begin(ia),end(ia),val);
cout << "the value" << val << (result == end(ia) ? " is not present" : " is present") << endl;
return 0;
}
當然,既然說find操作的是範圍,那麼它在序列的子範圍中查詢也是ok的。比如:
auto result=find(ia+1,ia+4,val);//在從陣列ia[1]到ia[4](不包活ia[4]的子範圍內查詢目標
注意:find作用的範圍始終是乙個半包閉區間 [ ),且find返回尾後迭代器用來表示未找到給定元素。
類似於find演算法,我們還有個count函式用於計算給定範圍類特定值出現的次數。
而accumulate也是一樣,用於計算序列的和,第三個引數是和的初始值,它在標頭檔案numeric中,當然這種求和以第三個引數型別為基礎,序列中的元素要能匹配到它的型別,當做字串加法(即字串連線)時,第三個引數應該顯示給出,比如:string(""),我們不能給乙個字串字面值,這樣傳遞的型別實際上是乙個const char * ,而它並沒有定義+運算子。對於唯讀演算法,我們最好使用cbegin()和cend(),若計畫想用演算法返回的迭代器來改變元素的值,就需要使用begin()和end()的結果作為引數。
————————————————————————————————————
二、泛型演算法永遠不會執行容器的操作(摘自premier)
泛型演算法本身是不會執行容器的操作的,它們只會執行於迭代器之上,執行對迭代器的操作,這樣,演算法永遠都不會改變底層容器的大小,注意只是不能改變大小,因為演算法可以改變容器中的值,或者移動元素,但永遠不會直接增加或刪除元素。基於此,泛型演算法又分為唯讀演算法和寫演算法。諸如find,count,accumulate,equal等演算法都是唯讀的。而寫容器元素的演算法必須注意確保序列原大小至少不小於我們要求演算法寫入的元素數目,因為我們的演算法是不執行容器操作的,即容器的大小不會變化。比如fill演算法,也是接受一對迭代器表示範圍,還接受第三個引數,fill將給定的這個值賦予輸入序列中的每個元素。
fill(vec.begin(),vec.end(),0);//將每個元素都重置為0,
fill_n(vec.begin(),n,val);//向給定賦值迭代器指向的元素開始處給n個元素賦新值val
————————————————————————————————————
使用fill_n時,要注意向目的位置迭代器寫入資料的演算法假定目的位置會足夠大,能容納要寫入的元素。比如我們不能用fill_n向乙個空向量寫入元素。但我們可以使用插入迭代器解決這個問題,插入迭代器可以保證演算法有足夠的元素空間來來容納資料,它是一種向容器中新增資料的迭代器。通常,通過迭代器向容器賦值時,值被賦予迭代器指向的元素,而通過插入迭代器則是新增元素到容器中。插入迭代器back_inserter接受乙個指向容器的引用,返回乙個與該容器繫結的插入迭代器,比如:
vectorvec;//空向量
fill_n(back_inserter(vec),10,0);//新增十個元素到vec
接下來還學習乙個個拷貝演算法
拷貝演算法copy接受三個迭代器,前兩個表範圍,第三個表目的序列的起始位置。即我們希望將給定範圍內的元素拷貝到目的序列中,傳遞給copy的目的序列至少要包含與輸入範圍序列一樣多的元素。例如:
int a1=;
int a2[sizeof(a1)/sizeof(*a1)];//a2與a1大小一樣
auto ret=copy(begin(a1),end(a1),a2);//把a1的內容拷貝給a2
還有乙個替換演算法replace,讀入乙個序列範圍,將序列中某個值全部用乙個新值來替換
replace(ilst.begin(),ilst.end(),0,42);
當然如果你並不希望源資料被改變,而只是想替換後放在另外乙個序列中,我們可以使用replace的拷貝版:replace_copy
replace_copy(ilst.cbegin(),ilst.cend(),back_inserter(ivec),0,42);
————————————————————————————————————
今天學到此吧,總結一下,一是泛型演算法都作用於迭代器上,實現了與具體容器相分離。二是各泛型演算法並不改變容器大小,當然有個back_insetter的傢伙,它可以繫結容器返回乙個插入迭代器,使用該迭代器賦值時會呼叫push_back,所以元素能追加到容器後,容器大小變化。三是幾個泛型演算法在用法上的相似性,即大多接受一對迭代器表示的範圍,針對這個範圍進行相關操作。
C primer筆記 泛型演算法
1 泛型演算法 演算法是因為其實現了一些經典演算法的公共介面,如排序和搜尋。泛型是因為他們可以作用於不同型別的元素和多種容器型別甚至是內建陣列。故稱泛型演算法 2 基本上都定義在algorithm和numeric兩個標頭檔案中,這些演算法遍歷由兩個迭代器指定的乙個元素範圍來進行操作,不對容器進行直接...
C Primer之泛型演算法lambda筆記
泛型演算法中有部分演算法除了第乙個和第二個引數接受迭代器型別來表示範圍外,它的第三個引數型別是乙個謂詞。謂詞是乙個可呼叫表示式,分為一元謂詞 只接受乙個引數 二元謂詞 接受兩個引數 比如說常用的sort演算法,它的第三個引數就是乙個二元謂詞。include include include inclu...
c primer學習筆記 初識泛型演算法
1概述 大多數演算法定義在標頭檔案algorithm中。一般情況下,這些演算法並不直接操作容器,而是遍歷迭代器指定的元素範圍。2迭代器使演算法不依賴於容器執行 雖然迭代器使用令演算法不依賴於容器型別,但大多數演算法都使用了乙個 或者多個 元素型別上的操作。關鍵在於 泛型演算法本身不會執行容器操作,只...