C 范型演算法

2021-08-03 03:12:26 字數 3547 閱讀 9180

泛型演算法本身不會執行容器的操作,它們只會執行於迭代器上,執行迭代器的操作。泛型演算法執行於迭代器智商而不會執行容器操作的特性帶來了乙個令人驚訝但非常必要的程式設計假定:演算法永遠不會改變底層容器的大小。演算法可能改變容器中儲存的原始的值,也可能子啊容器內移動元素,但永遠不會直接新增或刪除元素。

除了少數例外,標準庫演算法都對乙個範圍內的元素進行操作。我們將此元素範圍成為「輸入範圍」。帶有輸入範圍引數的演算法總是使用頭兩個形參標記該範圍。這兩個形參是分別指向要處理的第乙個元素和最後乙個元素的下一位置的迭代器。

例如:

find(begin(a),end(a),val);
再例如accumulate,頭兩個形參指定要累加的元素範圍。第三個形參則是累加的初值

int sum = accumulate(vec.cbegin(),vec.cend(),0);
accumulate將第三個引數作為求和起點,這蘊含著乙個程式設計假定:將元素型別加到和的型別上的操作必須可行。即,序列中元素的型別必須與第三個引數匹配,或者能夠轉換為第三個引數的型別。在上例中,vec元素可以是int,或者double,或者long long等。

下面是另乙個例子,由於string定義了+運算子,所以可以有:

string sum = accumulate(v.begin(),v.end(),string(""));
注意,我們顯式地建立了乙個string。將空串當做乙個字串字面值傳遞給了第三個引數是不可以的,原因在於 「」 物件型別是const char*.而如前所述,此型別決定了使用哪個+運算子。由於const char*沒有+運算子。此呼叫會產生錯誤。

一些演算法會自己向輸入範圍寫入元素。寫入到輸入序列的演算法本質上是安全的——只會寫入與指定輸入範圍數量相同的元素。

例如:

fill(vec.begin(),vec.end(),0);   //將每個元素重置為0
演算法不檢查寫操作

程式設計師的責任是保證輸入合法,因為演算法並不會幫我們檢查輸入是否合法。例如fill_n接受乙個迭代器、乙個計數值和乙個值。它將給定值賦予迭代器指向的元素開始的指定個元素。乙個初學者非常容易犯的錯誤就是在乙個空容器上呼叫fill_n(或者類似寫元素的演算法)

vector

vec;//空向量

//災難:修改vec中的10個(不存在)元素

fill_n(vec.begin(),10,0);

很多演算法都會比較輸入序列中的元素。預設情況下,這類演算法使用元素型別的《或==運算子完成比較。標準庫還為這些演算法定義了額外的版本,允許我們提供自己定義的操作來代替預設運算子。

例如sort。

謂詞謂詞是乙個可呼叫的表示式,其返回結果是乙個能作為條件的值。標準庫演算法使用的謂詞分為兩類:一元謂詞(unary predicate,意味著它們只接受單一引數)和二元謂詞(binary predicate,意味著它們有兩個引數)】

bool isshorter(const

string &s1, const

string &s2)

//按長度由短至長排序words

sort(words.begin(),words.end(),isshorter);

根據演算法接受一元謂詞還是二元謂詞,我們傳遞給演算法的謂詞必須嚴格接受乙個或兩個引數。但是,有時候我們希望接受更多引數,超出了演算法謂詞的限制。就要用到lambda表示式。我們可以向乙個演算法傳遞任何型別的可呼叫物件(callable object)。對於乙個物件或乙個表示式,如果可以對其使用呼叫運算子,則稱它為可呼叫的。呼叫運算子*****==》 ()

與任何函式類似,乙個lambda表示式具有乙個返回型別,乙個引數列表和乙個函式體。但是與函式不同,lambda可能定義在函式內部。乙個lambda表示式具有如下形式:

[capture list](parameter list) -> return type
其中,capture list(捕獲列表)是乙個lambda所在函式中定義的區域性變數的列表(通常為空);return type, parameter list, function body與任何普通函式一樣。但是lambda必須使用尾置返回來指定返回型別。

我們可以忽略引數列表和返回型別,但必須永遠包含捕獲列表和函式體

auto f =  ;

cout

<< f << endl;

向lambda傳遞引數

lambda不能有預設引數,因此呼叫的實參數目與形引數目相等。我們可以編寫乙個與isshorter函式完成相同功能的lambda:

sort(words.begin(),words.end(),(const

string &a,const

string &b));

使用捕獲列表

lambda表示式可以使用呼叫函式的區域性變數,但是必須指定。如要捕獲sz:

[sz](const string &a);
嫌麻煩就隱式,lambda表達是自己判斷

[=](const string &a);
上面是值捕獲,下面是引用捕獲

[&](const string &a);

下面是os顯示捕獲,引用捕獲方式;其他所有(c)隱式捕獲,值捕獲

[=,&os](const string &s);

需要注意的

一般lambda表示式只有乙個return語句,型別自己就可以判斷。如果多餘一條,則預設返回值為void,需要指定。指定要用尾置返回。

除了為每個容器定義的迭代器之外,標準庫在標頭檔案iterator中還定義了額外幾種迭代器。包括

它接受乙個容器,生成乙個迭代器,能實現向給定容器新增元素。有三種型別:

雖然iostream不是容器,但是有迭代器。通過使用流迭代器,我們可以用泛型演算法從流物件讀取資料以及向其寫入資料。

例如下面是乙個用istream_iterator從標準輸入讀取資料,存入乙個vector的例子:

istream_iterator in_iter(cin);//從cin中讀取int

istream_iterator eof; //當有資料可供讀取時

//後置遞增運算讀取流,返回迭代器的舊值

//解引用迭代器,獲得從流讀取的前乙個值

while(in_iter != eof)

vec.push_back(*in_iter++);

eof被定義為空的istream_iterator,從而可以當尾後迭代器來使用。對於乙個繫結到流的迭代器,一旦其關聯的流遇到檔案尾或遇到io錯誤,迭代器的值就與尾後迭代器相等。

可以用rbegin,rend,crbegin,crend來獲得。

sort(vec.rbegin(),vec.rend);//逆序排序

C 范型入門

范型是microsoft.net 2.0裡面乙個新加的內容,它使得c 語言更加完美。鑑於范型這個概念炒作炒得太虛,而缺少實際例子,使得很多菜鳥搞不懂這個概念,所以我來詳細說明1個例子程式,大家就能明白了。一 首先在vs2005環境裡面新建乙個控制台應用程式 console 二 完成如下 static...

c語言討論 范型程式設計

c語言中使用乙個變數之前要對其進行定義,那麼首先來看一下具體的乙個變數的定義。1.inta 10 2.charchartest 3.floatb 1.0 4.regest doublex 5.static int int ptr null 6.char words 10 10 1.c語言中型別及其作...

C 范型程式補充閱讀

1 下面程式通過輸入流迭代器來填充vector容器,通過輸出流迭代器來寫入 流cout 程式執行時,如果輸入為 1 2 3 4 5 q 則輸出為 1,2,3,4,5,1 2 3 4 5 請填空將程式補充完整。include include include using namespace std in...