c primer 筆記,第十章(泛型演算法)

2021-08-10 18:52:09 字數 4491 閱讀 3187

accumulate第三個三處所傳的儲值的型別必須定義了 「+」運算子,例如:將空串當作乙個字面值傳給第三個引數是不可以的

//會導致編譯錯誤,const char*上並沒有定義"+"運算子

string

sum= accumulate(v.cbegin(), v.cend(), "");

//string上定義了"+"運算子

string

sum= accumulate(v.cbegin(), v.cend(), string(""));

只接受乙個單一迭代器來表示第二個序列的演算法,都假設第二個序列至少與第乙個序列一樣長;

back_inserter是一種向容器中新增元素的迭代器,當我們通過此迭代器賦值時,賦值運算子會呼叫push_back;

vector

vec; //建立乙個空vector

fill_n(back_inserter(vec), 10, 0); //新增10個元素到vec

關於lambda表示式:

(1)表示乙個可呼叫的**單元,可以將其理解為乙個未命名(編譯器會給它命名)的內聯函式;其實是乙個函式物件,[ ] 稱為lambda introducer,取用外部的變數要放在[ ]中;

auto f =  ;

f(); // prints "hello lambda"

(2)可能定義在函式內部,必須使用尾置返回,不能有預設引數,可以直接使用定義在當前函式之外的名字,例如cout;

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

(4)可以傳值或者傳引用,要修改傳進來的資料必須在()後宣告 mutable;**獲的值是在建立時拷貝,而不是呼叫時拷貝;

(5)可以在lamada函式體內部像其他函式一樣定義static變數等等;

(6)可以使用隱式捕獲,但不推薦;

(7)當定義乙個lambda時,編譯器生成乙個與lambda對應的新的(未命名的類型別),使用auto定義乙個用lambda初始化的變數時,定義了乙個從lambda生成的型別的物件;

(8)lambda主要應用於原來我們傳給標準庫的一些函式的自定義引數時,比如sort函式,現在我們可以改用lambda表示式來自定義我們的比較函式,表達更方便;原來我們傳遞給標準庫有些函式(比如find_if)的任何函式都只能接受乙個引數,現在我們可以使用lambda來解決這個問題

int id = 0;

//由於是傳值,內部改變不會影響外部,並且對應於(4),**獲的值是在建立時拷貝,不是呼叫時拷貝

auto f = [id]()mutable ;

id = 42;

f(); f(); f(); //id:0 id:1 id:2

/*該lambda表示式可以類似為下面的class,但還有一些差別*/

class functor

};functor f;

佔位符,形式為_n,n表示第幾個引數;定義在名為placeholders的命名空間中,這個命名空間本身又定義在std中; using namespace std::placeholders; placeholders空間定義在functional標頭檔案中

可以將bind函式看做乙個通用的函式介面卡,可以使用佔位符對原函式重新包裝

(1)重排引數順序

//g是是乙個有兩個引數的可呼叫物件

auto g = bind(f, a, b, _2, c, _1);

//生成乙個新的可呼叫物件g,g的第一各引數被傳遞給f作為最後乙個引數,g的第二個引數被傳遞給f當做第三個引數

// 呼叫g(x, y); 相當於呼叫 f(a, b, y, c, x);

(2)繫結引用引數

//有些繫結的引數我們希望以引用方式傳遞,或者時要繫結的引數的型別無法拷貝(例如:ostream型別)

// bind只會拷貝傳給它的引數,如果我們希望傳遞給bind乙個物件又不拷貝它,就必須使用標準庫ref函式

for_each(words.begin(), words.end(),

bind()print, ref(os), _1, ' '));

流迭代器

(1)istream_iterator

// 從cin讀取int,一直到eof,將輸入的值用來構造vec

istream_iterator in_iter(cin), eof;

vector

vec(in_iter, eof);

// 也可以使用演算法來操作流迭代器,計算輸入的int型數字的和

cout

<< accumulate(in_iter, eof, 0) << endl;

(2)ostream_iterator

//使用ostream_iterator來輸出值的序列,每個元素輸出後還列印出乙個空格(也可以是其他字串,但必須是c風格的)

ostream_iterator out_iter(cout, " ");

for (auto e : vec)

*out_iter++ = e; //賦值語句實際上將元素寫到cout

cout << endl;

// 運算子*和++實際上對ostream_iterator物件那個不做任何事情,但是還是推薦這種寫法

//呼叫copy來列印vec中的元素,比迴圈更加簡單

copy(vec.begin(), vec.end(), out_iter);

cout << endl;

可以呼叫reverse_iterator的base成員來將乙個反向迭代器轉換成其對應的普通迭代器(即正向)

迭代器總共有5種,從下往上分別為繼承關係

(1)input iterator;

(2)output iterator;

(3)forward iterator;

(4)bidirectional iterator;

(5)random-access iterator;

//練習10.30

istream_iterator in_iter(cin), eof;

vector

vec(in_iter, eof);

sort(vec.begin(), vec.end());

ostream_iterator out_iter(cout, " ");

copy(vec.begin(), vec.end(), out_iter);

/*消除重複單詞,並統計長度大於sz的單詞數量*/

#include

#include

#include

#include

using

namespace

std;

void elimdups(vector

&words)

bool isshorter(const

string &s1, const

string &s2)

//根據ctr的數值來判斷返回單詞的單數還是複數形式

string make_plural(size_t ctr, const

string &word,

const

string &ending)

void biggies(vector

&words,

vector

::size_type sz)

); //獲取乙個迭代器,指向第乙個滿足size() >= sz 的元素

auto wc = find_if(words.begin(), words.end(),

[sz](const

string &a)

);//計算元素數目

auto count = words.end() - wc;

/* //直接呼叫count_if,獲得滿足size()>= sz的元素個數

auto count = count_if(words.begin(), words.end(),

[sz](const string &a)

);*/

cout

<< count << " "

<< make_plural(count, "word", "s")

<< " of length "

<< sz << " or longer "

<< endl;

for_each(wc, words.end(),

(const

string &s) );

cout

<< endl;

}int main()

; biggies(words, 5);

return

0;}

c primer 第十章泛型演算法lambda

謂詞是乙個呼叫表示式,其返回結果是乙個能用做條件的值。標準庫演算法為此分為兩類 1 一元謂詞 意味著只能接受單一引數 2 二元謂詞 意味著他們有兩個引數 接受謂詞的演算法對輸入序列中的元素呼叫謂詞。因此元素型別必須能轉換為謂詞的引數型別。以sort和isshorter舉例 eg bool issho...

c Primer 第十章 泛型演算法 重點梗概

演算法依賴於迭代器,而迭代器不依賴於容器,所以演算法不依賴於容器 但是演算法往往涉及比較,但是容器中的元素不一定定義了比較運算子,所以 大多數的演算法提供了一種方法,允許我們使用自定義的操作來代替預設的運算子 對於只讀取而不改變元素的演算法,最好使用cbegin cend 這裡要注意的是謂詞的種類,...

第十章 泛型演算法

特殊迭代器 插入迭代器 被繫結到乙個容器上,可用來向容器插入元素 流迭代器 被繫結到輸入 輸出流上,可用來遍歷所關聯io流 反向迭代器 向後而不是向前移動,除了forward list,容器都擁有它 移動迭代器 不是拷貝其中的元素,而是移動它們 插入迭代器操作 it t 在it指定的當前位置插入t,...