lambda与算法模板学习总结

来源:互联网 发布:念奴娇东方朔知乎 编辑:程序博客网 时间:2024/06/14 07:53

简要介绍 lambda拉姆达表达式
1、规则: [](入参表){函数的执行体;}
[](){} 类似一个匿名函数,没有函数名
2、lambda表达式中可以有返回值也可以没有返回值

示例代码的其他声明

class COdd{public:    bool operator() (int x)    {        return x & 1;    }};// 我们可以将 operator() 整体看做一个函数名,类似于下面的 IsOddclass 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