lambda與算法模板學習總結

簡要介紹 lambda拉姆達表達式
1、規則: [](入參表){函數的執行體;}
[](){} 類似一個匿名函數,沒有函數名
2、lambda表達式中可以有返回值也可以沒有返回值

示例代碼的其他聲明

class COdd
{
public:
    bool operator() (int x)
    {
        return x & 1;
    }
};// 我們可以將 operator() 整體看做一個函數名,類似於下面的 IsOdd

class AAA
{
private:
    int x;
    int y;
public:
    AAA() :x(0), y(0) {}
    AAA(int a, int b) :x(a), y(b) {}
    friend ostream& operator<< (ostream& os, const AAA& A)
    {
        os << "(" << A.x << ", " << A.y << ")";
        return os;
    }
    bool operator ==(const AAA& A)
    {
        if (this->x == A.GetX() && this->y == A.GetY())
            return true;
        return false;
    }
    int GetX() const { return x; };
    int GetY() const { return y; };
};

bool IsOdd(int x)
{
    return x & 1;
}

lambda與算法模板

算法模板的頭文件:#include <algorithm>
運行結果截圖在文章末尾
1、all_of、any_of、none_of
all_of:判斷某個區間的元素,是否【所有】都滿足某個條件
any_of :判斷某個區間的元素,是否【存在】都滿足某個條件
none_of :判斷某個區間的元素,是否【所有】都不滿足某個條件

    vector<AAA> aVec;
    vector<AAA>::iterator itAAA;
    deque<AAA> aDeq;

    vector<int> iVec;
    vector<int>::iterator itVec;
    deque<int> iDeq;
    deque<int>::iterator itDeq;

    iVec.assign({ 1,2,3,4,5,6,8,9,14 });
    bool bRet = false;
    bRet = all_of(iVec.begin(), iVec.begin() + 5, COdd());//判斷是否都滿足偶數
    bRet = all_of(iVec.begin(), iVec.begin() + 5, IsOdd);
    bRet = all_of(iVec.begin(), iVec.begin() + 5, [](int x) {return x & 1; });  // [](int x) {return x & 1; } 爲一個匿名函數,沒有函數
    bRet = any_of(iVec.begin(), iVec.end(), [](int x) {return !(x & 1); });//判斷是否存在偶數
    bRet = none_of(iVec.begin(), iVec.end(), [](int x) {return x > 10; });// 判斷是否都不滿足 > 10

2、for_each
for_each:對迭代器內的元素一次做某個操作

    cout << "\nfor_each輸出元素:";
    for_each(iVec.begin(), iVec.end(), [](int x) {cout << x << " "; });
    cout << endl;

3、find、find_if、find_if_not、find_end、find_first_of
find:查找等於某個元素的值(滿足條件的第一個值),返回迭代器
注:這裏會調用元素的 == 比較,如果爲對象需要重載 == 運算符
find_if:查找【第一個滿足】某個元素的值,返回迭代器
find_if_not:查找【第一個不滿足】某個元素的值,返回迭代器
find_end:查找子序列,返回最後一個子序列的起始位置,沒有查找到,返回 end()
注:!!!不是查找最後一個滿足的元素
find_first_of:在一個容器內,查找第一個出現在另一個容器裏的元素
注:!!!不是查找第一個子序列
adjacent_find:在序列中,查找第一對相鄰且相等元素的位置,返回前面元素的迭代器,沒有則返回end()

是否返回迭代器,根據 第三個參數,也就是 lambda 表達式 是否返回true

    aVec.assign({ AAA(),AAA(1,2),AAA(2,3), AAA(3,4),AAA(4,4) });
    itAAA = find(aVec.begin(), aVec.end(), AAA(1, 2));
    itAAA = find_if(aVec.begin(), aVec.end(), [](AAA A) {return A.GetX() == 2; });
    itAAA = find_if_not(aVec.begin(), aVec.end(), [](AAA A) {return A.GetX() == 0; });
    // find_end 在iVec中查找最後一個iDeq子序列,返回起始位置迭代器
    iVec.assign({ 1,2,3,4,5,2,3,6,2,3,7 });
    iDeq.assign({ 2,3 });// 2,3子序列
    itVec = find_end(iVec.begin(), iVec.end(), iDeq.begin(), iDeq.end());
    cout << "\n最後一個子序列的位置:";
    for_each(itVec, iVec.end(), [](int x) {cout << x << " "; });
    cout << endl;
    // find_first_of 
    iVec.assign({ 1,2,3,4,5 });
    iDeq.assign({ 8,7,6,5,4,3 });
    itVec = find_first_of(iVec.begin(), iVec.end(), iDeq.begin(), iDeq.end());
    cout << "\niVec中,第一個存在於iDeq中的元素:" << *itVec << endl;
    itDeq = find_first_of(iDeq.begin(), iDeq.end(), iVec.begin(), iVec.end());
    cout << "iDeq中,第一個存在於iVec中的元素:" << *itDeq << endl;
    // adjacent_find
    iVec.assign({ 1,2,3,4,5,5,4,3,2,1 });
    itVec = adjacent_find(iVec.begin(), iVec.end());// 默認 == 運算符比較
    cout << "第一對相鄰相等的元素:" << *itVec << "," << *(itVec + 1) << endl;

    aVec.assign({ AAA(),AAA(1,2),AAA(1,4),AAA(3,4),AAA(3,4),AAA(4,5) });
    itAAA = adjacent_find(aVec.begin(), aVec.end());// 默認 == 運算符比較
    cout << "第一對相鄰相等的元素:" << *itAAA << "," << *(itAAA + 1) << endl;
    itAAA = adjacent_find(aVec.begin(), aVec.end(),
        [](AAA A1, AAA A2) {return A1.GetX() == A2.GetX(); });
    cout << "第一對相鄰相等的元素:" << *itAAA << "," << *(itAAA + 1) << endl;
    // 解析:爲什麼不使用 cout << "第一對相鄰相等的元素:" << *itAAA << "," << *(++itAAA) << endl;或
    //                  cout << "第一對相鄰相等的元素:" << *itAAA << "," << *(itAAA++) << endl;
    //            而使用 cout << "第一對相鄰相等的元素:" << *itAAA << "," << *(itAAA+1) << endl;
    // cout 運算符,在調用的時候,會把需要輸出的東西一次壓棧
    // endl *(++itAAA) *itAAA -->壓棧的時候就做了 ++ 運算,後面壓入的*itAAA是執行了 ++ 之後的
    //itAAA = adjacent_find(aVec.begin(), aVec.end(),
    //  [](AAA A1, AAA A2) {return A1.GetX() == A2.GetX(); });
    //所以該示例中,使用 *(++itAAA)-> (1,4),(1,4)
    //                  *(itAAA++)->(1,4),(1,2)
    //                  *(itAAA+1)->(1,2),(1,4)//正確的輸出方式

4、count、count_if
count:統計序列中等於某個值的元素的個數
count_if:統計序列中滿足某個條件的元素個數

    iVec.assign({ 1,2,3,4,5,8,9,5,4,3,2,1 });
    int cnt = count(iVec.begin(), iVec.end(), 2);
    cout << "\niVec序列中等於2的元素的個數:" << cnt << endl;
    cnt = count_if(iVec.begin(), iVec.end(), [](int x) {return !(x & 1); });
    cout << "iVec序列中滿足爲偶數的元素個數:" << cnt << endl;

5、mismatch、equal、is_permutation
mismatch:比較兩個序列的元素,返回第一個對不相等的元素,默認爲 == 運算符比較,也可以自定義
第二個序列中只有起始位置(使用的時候,注意越界的問題)
第二個序列比第一個序列短,而第二個序列與第一個序列的前面的元素一樣,就會越界
解決辦法:使短的序列爲第一個序列
equal:判斷兩個序列是否相等
第二個序列只有起始位置(和 mismatch 一樣),同樣有越界問題
is_permutation:長序列前面的元素和短序列的所有元素比較,如果比較的元素是一樣的,只是順序不一樣,返回true,否則false

    iVec.assign({ 1,3,5,7,9,10,23,45 });
    iDeq.assign({ 1,3,5,7,8 });
    if (iVec.size() < iDeq.size())
    {
        pair<vector<int>::iterator, deque<int>::iterator> itPair;
        itPair = mismatch(iVec.begin(), iVec.end(), iDeq.begin());
        if (itPair.first == iVec.end())
            cout << "沒有查找到第一對不相等的元素" << endl;
        else
            cout << "\n第一對不相等的元素:" << *itPair.first << "," << *itPair.second << endl;
    }
    else
    {
        pair<deque<int>::iterator, vector<int>::iterator> itPair;
        itPair = mismatch(iDeq.begin(), iDeq.end(), iVec.begin());
        if (itPair.first == iDeq.end())
            cout << "沒有查找到第一對不相等的元素" << endl;
        else
            cout << "\n第一對不相等的元素:" << *itPair.first << "," << *itPair.second << endl;
    }

    aVec.assign({ AAA(), AAA(1, 2), AAA(3, 4), AAA(4, 5), AAA(2, 2) });
    aDeq.assign({ AAA(), AAA(1, 2), AAA(2, 4), AAA(4, 5) });
    if (aDeq.size() < aVec.size())
    {
        pair<deque<AAA>::iterator, vector<AAA>::iterator> itPair;
        itPair = mismatch(aDeq.begin(), aDeq.end(), aVec.begin(),
            [](AAA A1, AAA A2) {return (A1.GetX() == A2.GetX()) && (A1.GetY() == A2.GetY()); });
        cout << "\n第一對不相等的元素:" << *itPair.first << "," << *itPair.second << endl;
    }
    else
    {
        // ...
    }

    iVec.assign({ 1,3,5,7,9 });
    iDeq.assign({ 1,3,5,7,9,2,4,6,8 });
    if (iVec.size() < iDeq.size())
    {
        //bRet = equal(iVec.begin(), iVec.end(), iDeq.begin());
        bRet = equal(iVec.begin(), iVec.end(), iDeq.begin(), [](int a, int  b) {return a == b; });
        cout << "equals?:" << (bRet ? "Yes" : "No") << endl;
    }
    else
    {
        // ...
    }

    iVec.assign({ 1,3,5,7,9 });
    iDeq.assign({ 5,9,7,1,3,12,3,4,5 });
    if (iVec.size() < iDeq.size())
    {
        //bRet = is_permutation(iVec.begin(), iVec.end(), iDeq.begin());
        bRet = is_permutation(iVec.begin(), iVec.end(), iDeq.begin(), [](int a, int  b) {return a == b; });
        cout << "IsPermutation:" << (bRet ? "Yes" : "No") << endl;
    }
    else
    {
        bRet = is_permutation(iDeq.begin(), iDeq.end(), iVec.begin());
        cout << "IsPermutation:" << (bRet ? "Yes" : "No") << endl;
    }

6、search、search_n
search:查找第一個子序列,與find_end對應,返回子序列起始位置的迭代器
search_n:查找連續n個等於某個值的元素位置,返回起始位置的迭代器

    iVec.assign({ 1,2,3,4,5,3,4,5,6,5,6,9 });
    iDeq.assign({ 4,5 });
    //itVec = search(iVec.begin(), iVec.end(), iDeq.begin(), iDeq.end());// 默認 == 運算符
    itVec = search(iVec.begin(), iVec.end(), iDeq.begin(), iDeq.end(), [](int a, int b) {return a == b; });
    cout << "\n第一個子序列位置:";
    for_each(itVec, iVec.end(), [](int x) {cout << x << " "; });
    cout << endl;

    iVec.assign({ 1,2,2,2,3,4,4,4,5,2,2,2,7 });
    //itVec = search_n(iVec.begin(), iVec.end(), 3, 2);// 查找3個連續等於2的元素位置, 默認 == 運算符
    itVec = search_n(iVec.begin(), iVec.end(), 3, 2, [](int a, int b) {return a == b; });
    cout << "3個連續等於2的元素位置:";
    for_each(itVec, iVec.end(), [](int x) {cout << x << " "; });
    cout << endl;

7、copy、copy_n、copy_if、copy_backward
copy:把第一個序列的元素,拷貝到第二個序列
要求第二個序列足夠(保證不越界)
copy_n:指定長度拷貝,拷貝第一個序列 n 個長度的元素到第二個序列
copy_if:拷貝區間中滿足某個條件的元素
copy_backward:指定結束位置,從後往前拷貝

    iVec.assign({ 1,3,5,7,9 });
    iDeq.assign({ 2,4,6,8 });
    //copy(iVec.begin(), iVec.end(), iDeq.begin());// 報錯,4<5, 空間不足,訪問越界
    iDeq.resize(iVec.size());
    copy(iVec.begin(), iVec.end(), iDeq.begin());
    cout << "\niDeq中的元素:";
    for_each(iDeq.begin(), iDeq.end(), [](int x) {cout << x << " "; });
    cout << endl;

    iVec.assign({ 1,3,5,7,9 });
    iDeq.assign({ 2,4,6,8 });
    copy_n(iVec.begin(), 3, iDeq.begin());
    cout << "iDeq中的元素:";
    for_each(iDeq.begin(), iDeq.end(), [](int x) {cout << x << " "; });
    cout << endl;

    // 把 iVec 中所有偶數,拷貝到 iDeq 中
    iVec.assign({ 1,2,3,4,5,6,7,8,9 });
    iDeq.resize(iVec.size());
    copy_if(iVec.begin(), iVec.end(), iDeq.begin(), [](int x) {return !(x & 1); });
    cout << "iDeq中的元素:";
    for_each(iDeq.begin(), iDeq.end(), [](int x) {cout << x << " "; });
    cout << endl;

    iVec.assign({ 1,2,3,4,5,6,7 });
    iDeq.assign({ 11,22,33,44,55 });
    copy_backward(iDeq.begin(), iDeq.end(), iVec.end());
    cout << "iVec中的元素:";
    for_each(iVec.begin(), iVec.end(), [](int x) {cout << x << " "; });
    cout << endl;

8、move
move:移動元素,但是這個移動元素,源序列的元素是不變的,效果和copy一樣
注:copy與move的區別:就和memmove與memcpy一樣
源內存和目的內存不一樣的情況下,兩個函數功能一樣
源內存和目的內存重合的情況下,例如:char arr[]={1,2,3,4};
memmove(arr,arr+1,3)=>arr[]={1,1,1,1}
memmcpy(arr,arr+1,3)=>arr[]={1,1,2,3}

    iVec.assign({ 1,2,3,4,5,6 });
    move(iVec.begin(), iVec.end() - 1, iVec.begin() + 1);
    cout << "\niVec中的元素:";
    for_each(iVec.begin(), iVec.end(), [](int x) {cout << x << " "; });
    cout << endl;

    iDeq.assign({ 1,2,3,4,5,6 });
    copy(iDeq.begin(), iDeq.end() - 1, iDeq.begin() + 1);
    cout << "iDeq中的元素:";
    for_each(iDeq.begin(), iDeq.end(), [](int x) {cout << x << " "; });
    cout << endl;

9、swap、iter_swap、swap_ranges
swap:交換兩個元素的值(如果入參是迭代器,交換的就是迭代器的值)
iter_swap:交換兩個迭代器指向的元素的值
swap_ranges:交換一段區間的元素值

    list<int> iList1({ 1,3,5,7 });
    list<int> iList2({ 2,4,6,8 });
    list<int>::iterator it1, it2;

    it1 = iList1.begin();
    it2 = iList2.begin();
    swap(it1, it2);// ==> 交換兩個迭代器的值
    cout << "\nswap:" << iList2.front() << "--" << *it2 << endl;

    it1 = iList1.begin();
    it2 = iList2.begin();
    iter_swap(it1, it2);// ==> 交換兩個迭代器指向的元素的值
    cout << "iter_swap:" << iList2.front() << "--" << *it2 << endl;

    iList1.assign({ 1,3,5,7,9 });
    iList2.assign({ 2,4,6,8,10 });
    swap_ranges(iList1.begin(), --iList1.end(), iList2.begin());
    for_each(iList2.begin(), iList2.end(), [](int x) {cout << x << " "; });
    cout << endl;

10、transform
transform:把一段區間的元素,做某個處理後,存入另外一個區間

    iVec.assign({ 1,3,5,7,9 });
    iDeq.resize(iVec.size());
    transform(iVec.begin(), iVec.end(), iDeq.begin(), [](int x) {return x + x; });
    cout << "\niDeq:";
    for_each(iDeq.begin(), iDeq.end(), [](int x) {cout << x << " "; });
    cout << endl;

    vector<string> sVec({ "aa","sdc","abc","werdd","rtuf" });
    iDeq.resize(sVec.size());
    transform(sVec.begin(), sVec.end(), iDeq.begin(), [](string s) {return s.length(); });
    cout << "iDeq:";
    for_each(iDeq.begin(), iDeq.end(), [](int x) {cout << x << " "; });
    cout << endl;

11、repalce、repalce_if、repalce_copy、replace_copy_if
repalce:把區間等於某個值的元素替換成另一個
repalce_if:把區間中,所有滿足某個條件的元素替換成另一個
repalce_copy:把replace替換的結果存入另一個區間,源區間保存不變
replace_copy_if:把replace_if替換的結果存入另一個區間,源區間保存不變

    iVec.assign({ 1,3,5,3,9 });
    replace(iVec.begin(), iVec.end(), 3, 9);// 把3替換成9

    iVec.assign({ 1,2,3,4,5,6,7 });
    replace_if(iVec.begin(), iVec.end(), [](int x) {return x & 1; }, 0);// 滿足條件的替換爲 0

    iDeq.resize(iVec.size());
    replace_copy(iVec.begin(), iVec.end(), iDeq.begin(), 1, 2);

12、fill、fill_n
fill:把某個區間填爲某個值
fill_n:指定區間起始位置,填充 n 個元素爲某個值(類似memset)

    iVec.assign({ 1,3,5,7,9 });
    fill(iVec.begin(), iVec.begin() + 3, 0);//=> 0 0 0 7 9
    fill_n(iVec.begin(), 3, 1);//=> 1 1 1 7 9

13、generate
generate:按照某個規則生成元素,一次賦值給區間的元素

    iVec.resize(10);
    generate(iVec.begin(), iVec.end(), []()// 填寫 10 個偶數
    {
        static int i = 0;
        i += 2;
        return i;
    });
    cout << "\niVec:";
    for_each(iVec.begin(), iVec.end(), [](int x) {cout << x << " "; });
    cout << endl;

運行截圖:
這裏寫圖片描述
有些是沒有輸出的,寫到後面越來越懶,沒寫輸出直接查看內存了
示例源碼:https://pan.baidu.com/s/1mhXwr6w

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