C++ Primer5 第十章 學習筆記

10.2、初識泛型算法

1、只讀算法


//對vec中的元素求和,和的初值是0,頭文件是numeric
int sum = accumulate(vec.cbegin(), vec.cend(), 0);

//將vector中所有的string元素連接起來
string sum = accumulate(v.cbegin(), v.cend(), string(""));

//equal用於確定兩個序列是否保存相同的值,第二個序列元素數目至少應該與第一個一樣多
equal(roster1.cbegin(), roster1.cend(), roster2.cbegin());

2、寫容器元素的算法

//將每個元素重置爲0
fill(vec.begin(), vec.end(), 0);

vector<int> vec;
fill_n(vec.begin(), vec.size(), 0);//將所有元素重置爲0,不可指定大小,算法不檢查寫操作
fill_n(back_inserter(vec), 10, 0);  //添加10個元素到vec

back_inserter接受一個指向容器的引用,返回一個與該容器綁定的插入迭代器。頭文件iterator

int a1[] = {0,1,2,3,4,5,6,7,8,9};
int a2[sizeof(a1)/sizeof(*a1)]; //a2與a1大小一樣
//ret指向拷貝到a2的尾元素之後的位置
auto ret = copy(begin(a1), end(a2), a2); //把a1的內容拷貝給a2
//將所有值爲0的元素改爲42
replace(ilist.begin(), ilist.end(), 0, 42);
//使用back_inserter按需要增長目標序列
replace_copy(ilist.cegin(), ilist.cend(), back_inserter(ivec), 0, 42);
//此調用後,ilist並未改變,ivec包含ilist的一份拷貝,不過原來在ilist中值爲0的元素改爲42

3、重排容器元素的算法

//練習10.9 
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>

using namespace std;

inline void output_words(vector<string> &words) //輸出
{
    for(auto iter = words.begin(); iter != words.end(); iter++)
        cout << *iter << " ";
    cout << endl;
}

void elimDups(vector<string> &words)
{
    output_words(words);

    sort(words.begin(), words.end());       //按字典序排序,以便查找重複單詞
    output_words(words);

    //unique重排輸入範圍,使得每個單詞只出現一次
    //排列在範圍前部,返回指向不重複區域之後一個位置的迭代器
    auto end_unique = unique(words.begin(), words.end());
    output_words(words);

    //使用向量操作erase刪除重複單詞
    words.erase(end_unique, words.end());
    output_words(words);
}

int main(int argc, char *argv[])
{
    ifstream in(argv[1]);
    if(!in){
        cout << "打開輸入文件失敗!" << endl;
        exit(1);
    }

    vector<string> words;
    string word;
    while(in >> word)
        words.push_back(word);
    
    elimDups(words);

    return 0;
}

10.3 定製操作

1、向算法傳遞函數

stable_sort 穩定排序算法,可以維持相等元素的原有順序。

//練習10.13
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>

using namespace std;

inline void output_words(vector<string>::iterator beg, vector<string>::iterator end) //輸出
{
    for(auto iter = beg; iter != end; iter++)
        cout << *iter << " ";
    cout << endl;
}

bool five_or_more(const string &s1)   //找出大於5的string,返回true
{
    return s1.size() >= 5;
}

int main(int argc, char *argv[])
{
    ifstream in(argv[1]);
    if(!in){
        cout << "打開輸入文件失敗!" << endl;
        exit(1);
    }

    vector<string> words;
    string word;
    while(in >> word)
        words.push_back(word);
    output_words(words.begin(), words.end());
    //partition接受一個謂詞,對容器內容進行劃分,true排在容器的前半部分,false排在後半部分
    auto iter = partition(words.begin(), words.end(), five_or_more);
    output_words(words.begin(), words.end());

    return 0;
}

2、lambda表達式

可調用對象,函數、函數指針、重載了函數調用運算符的類、lambda表達式。

一個lambda表達式表示一個可調用的代碼單元,可理解爲一個未命名的內聯函數。

[capture list] (parameter list) -> return type {function body}

參數列表和返回類型可忽略,必須包含捕獲列表(一個lambda所在函數中定義的局部變量的列表)和函數體。

//第三個參數爲lambda表達式,實現isShorter的功能
stable_sort(words.begin(), words.end(), [](const string &a, const string &b)
                                            { return a.size() < b.size();});

上面空的捕獲列表表明此lambda表達式不使用它所在函數中的任何局部變量。

//練習10.16
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>

using namespace std;

inline void output_words(vector<string> &words) //輸出
{
    for(auto iter = words.begin(); iter != words.end(); iter++)
        cout << *iter << " ";
    cout << endl;
}

void elimDups(vector<string> &words)
{
    sort(words.begin(), words.end());       //按字典序排序,以便查找重複單詞
    output_words(words);

    //unique重排輸入範圍,使得每個單詞只出現一次
    //排列在範圍前部,返回指向不重複區域之後一個位置的迭代器
    auto end_unique = unique(words.begin(), words.end());

    //使用向量操作erase刪除重複單詞
    words.erase(end_unique, words.end());
}

string make_plural(size_t ctr, const string &word, const string &ending)
{
    return (ctr > 1) ? word + ending : word;
}

void biggies(vector<string> &words, vector<string>::size_type sz)
{
    elimDups(words);            //將words按字典序排序,刪除重複單詞
    //按長度排序,長度相同的單詞維持字典序
    stable_sort(words.begin(), words.end(), 
                [](const string &a, const string &b)
                  { return a.size() < b.size(); });
    //獲取一個迭代器,指向第一個滿足size() >= sz的元素
    auto wc = find_if(words.begin(), words.end(), [sz](const string &a)
                                                  { return a.size() >= sz; });
    //計算滿足size >= sz的元素的數目
    auto count = words.end() - wc;
    cout << count << " " << make_plural(count, "word", "s")
         << " of length " << sz << " or longer" << endl;
    //打印長度大於等於給定值的單詞,每個單詞後面接一個空格
    for_each(wc, words.end(), [](const string &s){cout << s << " ";});
    cout << endl;
}

int main(int argc, char *argv[])
{
    ifstream in(argv[1]);
    if(!in){
        cout << "打開輸入文件失敗!" << endl;
        exit(1);
    }

    vector<string> words;
    string word;
    while(in >> word)
        words.push_back(word);
    
    biggies(words, 4);

    return 0;
}

3、lambda捕獲和返回

值捕獲:與參數不同,被捕獲的變量的值是在lambda創建時拷貝,而不是調用時拷貝。

引用捕獲:當以引用方式捕獲一個變量時,必須保證在lambda執行時變量是存在的。

隱式捕獲:&隱式引用捕獲,=隱式值捕獲,顯式捕獲可以和隱式捕獲混合使用

可變lambda:值捕獲的方式可以加mutable改變值,引用捕獲取決於是否const

指定lambda返回類型:使用尾置返回類型

4、參數綁定

標準庫bind函數:   auto newCallable = bind(callable, arg_list)    newCallable本身是一個可調用對象,arg_list是一個逗號分隔的參數列表,對應給定的callable的參數。   arg_list參數可能包含形如_n的名字,n爲整數,這些參數是“佔位符”。數值n表示生成的可調用對象中參數的位置。頭文件 functional。   

//練習10.22
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<algorithm>
#include<functional>

using namespace std;
using namespace std::placeholders;

inline void output_words(vector<string> &words) //輸出
{
    for(auto iter = words.begin(); iter != words.end(); iter++)
        cout << *iter << " ";
    cout << endl;
}

bool check_size(const string &s, string::size_type sz)
{
    return s.size() >= sz;
}

string make_plural(size_t ctr, const string &word, const string &ending)
{
    return (ctr > 1) ? word + ending : word;
}

void biggies(vector<string> &words, vector<string>::size_type sz)
{
    output_words(words);
    
    //計算滿足size >= sz的元素的數目
    //count_if:接受一對迭代器,和一個謂詞,返回一個計數值,表示謂詞有多少次爲真。
    auto bc = count_if(words.begin(), words.end(), bind(check_size, _1, sz));
    cout << bc << " " << make_plural(bc, "word", "s")
         << " of length " << sz << " or longer" << endl;
}

int main(int argc, char *argv[])
{
    ifstream in(argv[1]);
    if(!in){
        cout << "打開輸入文件失敗!" << endl;
        exit(1);
    }

    vector<string> words;
    string word;
    while(in >> word)
        words.push_back(word);
    
    biggies(words, 6);

    return 0;
}

10.4、再探迭代器

1、插入迭代器

back_inserter    front_inserter    inserter

2、iostream迭代器

 

3、反向迭代器

流迭代器和forward_list不支持創建反向迭代器。

//10.37給定一個包含10個元素的vector,將位置3到7之間的元素按逆序拷貝到一個list中
#include<iostream>
#include<vector>
#include<algorithm>
#include<list>
#include<iterator>

using namespace std;

int main()
{
    vector<int> vi = {0,1,2,3,4,5,6,7,8,9};
    ostream_iterator<int> out_iter(cout, " ");

    copy(vi.cbegin(), vi.cend(), out_iter);
    cout << endl;

    list<int> li;
    vector<int>::reverse_iterator re(vi.begin() + 2);
    vector<int>::reverse_iterator rb(vi.begin() + 7);

    copy(rb, re, back_inserter(li));
    copy(li.begin(), li.end(), out_iter);
    cout << endl;

    return 0;
}

10.5、泛型算法結構

1、5類迭代器

2、算法形參模式

10.6、特定容器算法

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章