{"id":"58954498","type":"page","status":"current","title":"04.常用算法","version":{"by":{"type":"known","username":"ethanliu","userKey":"2c90931b6cfb654f016d5c69becc0001","profilePicture":{"path":"/images/icons/profilepics/default.svg","width":48,"height":48,"isDefault":true},"displayName":"刘浩","_links":{"self":"https://wiki.suncaper.net/rest/api/user?key=2c90931b6cfb654f016d5c69becc0001"},"_expandable":{"status":""}},"when":"2022-07-09T01:51:25.000Z","message":"","number":1,"minorEdit":false,"hidden":false,"_links":{"self":"https://wiki.suncaper.net/rest/experimental/content/58954498/version/1"},"_expandable":{"content":"/rest/api/content/58954498"}},"body":{"storage":{"value":"

4.1 函数对象

重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。

注意:

1.函数对象(仿函数)是一个类,不是一个函数。

2.函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。

分类:假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数binary functor)。

函数对象的作用主要是什么?STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算,另一版本则允许用户通过template参数的形式来指定所要采取的策略。

cpp

总结:

1、函数对象通常不定义构造函数和析构函数,所以在构造和析构时不会发生任何问题,避免了函数调用的运行时问题。

2、函数对象超出普通函数的概念,函数对象可以有自己的状态

3、函数对象可内联编译,性能好。用函数指针几乎不可能

4、模版函数对象使函数对象具有通用性,这也是它的优势之一 


4.2 谓词

谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词,谓词可作为一个判断式

cpp 5;\n\t}\n\n};\n//一元谓词\nvoid test01()\n{\n\tvector v;\n\tfor (int i = 0; i < 10;i ++)\n\t{\n\t\tv.push_back(i);\n\t}\n\t\n\t vector::iterator it = find_if(v.begin(), v.end(), GreaterThenFive());\n\t if (it == v.end())\n\t {\n\t\t cout << \"没有找到\" << endl;\n\t }\n\t else\n\t {\n\t\t cout << \"找到了: \" << *it << endl;\n\t }\n}\n\n//二元谓词\nclass MyCompare\n{\npublic:\n\tbool operator()(int num1, int num2)\n\t{\n\t\treturn num1 > num2;\n\t}\n};\n\nvoid test02()\n{\n\tvector v;\n\tv.push_back(10);\n\tv.push_back(40);\n\tv.push_back(20);\n\tv.push_back(90);\n\tv.push_back(60);\n\n\t//默认从小到大\n\tsort(v.begin(), v.end());\n\tfor (vector::iterator it = v.begin(); it != v.end();it++)\n\t{\n\t\tcout << *it << \" \";\n\t}\n\tcout << endl;\n\tcout << \"----------------------------\" << endl;\n\t//使用函数对象改变算法策略,排序从大到小\n\tsort(v.begin(), v.end(),MyCompare());\n\tfor (vector::iterator it = v.begin(); it != v.end(); it++)\n\t{\n\t\tcout << *it << \" \";\n\t}\n\tcout << endl;\n}]]>

4.3 内建函数对象

STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。使用内建函数对象,需要引入头文件 #include<functional>。

 

  • 6个算数类函数对象,除了negate是一元运算,其他都是二元运算。

template<class T> T plus<T>//加法仿函数

template<class T> T minus<T>//减法仿函数

template<class T> T multiplies<T>//乘法仿函数

template<class T> T divides<T>//除法仿函数

template<class T> T modulus<T>//取模仿函数

template<class T> T negate<T>//取反仿函数

 

  • 6个关系运算类函数对象,每一种都是二元运算。

template<class T> bool equal_to<T>//等于

template<class T> bool not_equal_to<T>//不等于

template<class T> bool greater<T>//大于

template<class T> bool greater_equal<T>//大于等于

template<class T> bool less<T>//小于

template<class T> bool less_equal<T>//小于等于

 

  • 逻辑运算类运算函数,not为一元运算,其余为二元运算。

template<class T> bool logical_and<T>//逻辑与

template<class T> bool logical_or<T>//逻辑或

template<class T> bool logical_not<T>//逻辑非


内建函数对象举例:


cpp n;\n\tcout << n(50) << endl;\n}\n\n//加法仿函数\nvoid test02()\n{\n\tplus p;\n\tcout << p(10, 20) << endl;\n}\n\n//大于仿函数\nvoid test03()\n{\n\tvector v;\n\tsrand((unsigned int)time(NULL));\n\tfor (int i = 0; i < 10; i++){\n\t\tv.push_back(rand() % 100);\n\t}\n\n\tfor (vector::iterator it = v.begin(); it != v.end(); it++){\n\t\tcout << *it << \" \";\n\t}\n\tcout << endl;\n\tsort(v.begin(), v.end(), greater());\n\n\tfor (vector::iterator it = v.begin(); it != v.end(); it++){\n\t\tcout << *it << \" \";\n\t}\n\tcout << endl;\n\n}\n\n]]>

3.1.4 函数对象适配器

cpp\n{\npublic:\n\tvoid operator()(int v1,int v2) const\n\t{\n\t\tcout << \"v1 = : \" << v1 << \" v2 = :\" <v;\n\tfor (int i = 0; i < 10; i++)\n\t{\n\t\tv.push_back(i);\n\t}\n\tcout << \"请输入起始值:\" << endl;\n\tint x;\n\tcin >> x;\n\n\tfor_each(v.begin(), v.end(), bind1st(MyPrint(), x));\n\t//for_each(v.begin(), v.end(), bind2nd( MyPrint(),x ));\n}\n//总结: bind1st和bind2nd区别?\n//bind1st : 将参数绑定为函数对象的第一个参数\n//bind2nd : 将参数绑定为函数对象的第二个参数\n//bind1st bind2nd将二元函数对象转为一元函数对象\n\n\nclass GreaterThenFive:public unary_function\n{\npublic:\n\tbool operator ()(int v) const\n\t{\n\t\treturn v > 5;\n\t}\n};\n\n//2、取反适配器\nvoid test02()\n{\n\tvector v;\n\tfor (int i = 0; i < 10;i++)\n\t{\n\t\tv.push_back(i);\n\t}\n\t\n// \tvector::iterator it = find_if(v.begin(), v.end(), GreaterThenFive()); //返回第一个大于5的迭代器\n//\tvector::iterator it = find_if(v.begin(), v.end(), not1(GreaterThenFive())); //返回第一个小于5迭代器\n\t//自定义输入\n\tvector::iterator it = find_if(v.begin(), v.end(), not1 ( bind2nd(greater(),5)));\n\tif (it == v.end())\n\t{\n\t\tcout << \"没找到\" << endl;\n\t}\n\telse\n\t{\n\t\tcout << \"找到\" << *it << endl;\n\t}\n\n\t//排序 二元函数对象\n\tsort(v.begin(), v.end(), not2(less()));\n\tfor_each(v.begin(), v.end(), [](int val){cout << val << \" \"; });\n\n}\n//not1 对一元函数对象取反\n//not2 对二元函数对象取反\n\nvoid MyPrint03(int v,int v2)\n{\n\tcout << v + v2<< \" \";\n}\n\n//3、函数指针适配器 ptr_fun\nvoid test03()\n{\n\tvector v;\n\tfor (int i = 0; i < 10; i++)\n\t{\n\t\tv.push_back(i);\n\t}\n\t// ptr_fun( )把一个普通的函数指针适配成函数对象\n\tfor_each(v.begin(), v.end(), bind2nd( ptr_fun( MyPrint03 ), 100));\n}\n\n\n//4、成员函数适配器\nclass Person\n{\npublic:\n\tPerson(string name, int age)\n\t{\n\t\tm_Name = name;\n\t\tm_Age = age;\n\t}\n\n\t//打印函数\n\tvoid ShowPerson(){\n\t\tcout << \"成员函数:\" << \"Name:\" << m_Name << \" Age:\" << m_Age << endl;\n\t}\n\tvoid Plus100()\n\t{\n\t\tm_Age += 100;\n\t}\npublic:\n\tstring m_Name;\n\tint m_Age;\n};\n\nvoid MyPrint04(Person &p)\n{\n\tcout << \"姓名:\" << p.m_Name << \" 年龄:\" << p.m_Age << endl;\n\n};\n\nvoid test04()\n{\n\tvector v;\n\tPerson p1(\"aaa\", 10);\n\tPerson p2(\"bbb\", 20);\n\tPerson p3(\"ccc\", 30);\n\tPerson p4(\"ddd\", 40);\n\tv.push_back(p1);\n\tv.push_back(p2);\n\tv.push_back(p3);\n\tv.push_back(p4);\n\n\t//for_each(v.begin(), v.end(), MyPrint04);\n\t//利用 mem_fun_ref 将Person内部成员函数适配\n\tfor_each(v.begin(), v.end(), mem_fun_ref(&Person::ShowPerson));\n// \tfor_each(v.begin(), v.end(), mem_fun_ref(&Person::Plus100));\n// \tfor_each(v.begin(), v.end(), mem_fun_ref(&Person::ShowPerson));\n}\n\nvoid test05(){\n\n\tvector v1;\n\t//创建数据\n\tPerson p1(\"aaa\", 10);\n\tPerson p2(\"bbb\", 20);\n\tPerson p3(\"ccc\", 30);\n\tPerson p4(\"ddd\", 40);\n\n\tv1.push_back(&p1);\n\tv1.push_back(&p2);\n\tv1.push_back(&p3);\n\tv1.push_back(&p4);\n\n\tfor_each(v1.begin(), v1.end(), mem_fun(&Person::ShowPerson));\n}\n\n//如果容器存放的是对象指针, 那么用mem_fun\n//如果容器中存放的是对象实体,那么用mem_fun_ref]]>

4.2 算法概述

算法主要是由头文件<algorithm> <functional> <numeric>组成。

<algorithm>是所有STL头文件中最大的一个,其中常用的功能涉及到比较,交换,查找,遍历,复制,修改,反转,排序,合并等...

<numeric>体积很小,只包括在几个序列容器上进行的简单运算的模板函数.

<functional> 定义了一些模板类,用以声明函数对象。

4.3 常用遍历算法

/*

    遍历算法 遍历容器元素

    @param beg 开始迭代器

    @param end 结束迭代器

    @param _callback  函数回调或者函数对象

    @return 函数对象

*/

for_each(iterator beg, iterator end, _callback);

/*

    transform算法 将指定容器区间元素搬运到另一容器中

    注意 : transform 不会给目标容器分配内存,所以需要我们提前分配好内存

    @param beg1 源容器开始迭代器

    @param end1 源容器结束迭代器

    @param beg2 目标容器开始迭代器

    @param _cakkback 回调函数或者函数对象

    @return 返回目标容器迭代器

*/

transform(iterator beg1, iterator end1, iterator beg2, _callbakc)

for_each:

cpp inline\nvoid for_each(_InIt _First, _InIt _Last, _Fn1 _Func)\n{\n\tfor (; _First != _Last; ++_First)\n\t\t_Func(*_First);\n}\n\n*/\n\n//普通函数\nvoid print01(int val){\n\tcout << val << \" \";\n}\n//函数对象\nstruct print001{\n\tvoid operator()(int val){\n\t\tcout << val << \" \";\n\t}\n};\n\n//for_each算法基本用法\nvoid test01(){\n\t\n\tvector v;\n\tfor (int i = 0; i < 10;i++){\n\t\tv.push_back(i);\n\t}\n\n\t//遍历算法\n\tfor_each(v.begin(), v.end(), print01);\n\tcout << endl;\n\n\tfor_each(v.begin(), v.end(), print001());\n\tcout << endl;\n\n}\n\nstruct print02{\n\tprint02(){\n\t\tmCount = 0;\n\t}\n\tvoid operator()(int val){\n\t\tcout << val << \" \";\n\t\tmCount++;\n\t}\n\tint mCount;\n};\n\n//for_each返回值\nvoid test02(){\n\n\tvector v;\n\tfor (int i = 0; i < 10; i++){\n\t\tv.push_back(i);\n\t}\n\n\tprint02 p = for_each(v.begin(), v.end(), print02());\n\tcout << endl;\n\tcout << p.mCount << endl;\n}\n\nstruct print03 : public binary_function{\n\tvoid operator()(int val,int bindParam) const{\n\t\tcout << val + bindParam << \" \";\n\t}\n};\n\n//for_each绑定参数输出\nvoid test03(){\n\t\n\tvector v;\n\tfor (int i = 0; i < 10; i++){\n\t\tv.push_back(i);\n\t}\n\n\tfor_each(v.begin(), v.end(), bind2nd(print03(),100));\n}]]>

transform:

cpp inline \n\t_OutIt _Transform(_InIt _First, _InIt _Last,_OutIt _Dest, _Fn1 _Func)\n\t{\t\n\n\t\tfor (; _First != _Last; ++_First, ++_Dest)\n\t\t\t*_Dest = _Func(*_First);\n\t\treturn (_Dest);\n\t}\n\n\ttemplate inline\n\t_OutIt _Transform(_InIt1 _First1, _InIt1 _Last1,_InIt2 _First2, _OutIt _Dest, _Fn2 _Func)\n\t{\t\n\t\tfor (; _First1 != _Last1; ++_First1, ++_First2, ++_Dest)\n\t\t\t*_Dest = _Func(*_First1, *_First2);\n\t\treturn (_Dest);\n\t}\n*/\n\nstruct transformTest01{\n\tint operator()(int val){\n\t\treturn val + 100;\n\t}\n};\nstruct print01{\n\tvoid operator()(int val){\n\t\tcout << val << \" \";\n\t}\n};\nvoid test01(){\n\n\tvector vSource;\n\tfor (int i = 0; i < 10;i ++){\n\t\tvSource.push_back(i + 1);\n\t}\n\n\t//目标容器\n\tvector vTarget;\n\t//给vTarget开辟空间\n\tvTarget.resize(vSource.size());\n\t//将vSource中的元素搬运到vTarget\n\tvector::iterator it = transform(vSource.begin(), vSource.end(), vTarget.begin(), transformTest01());\n\t//打印\n\tfor_each(vTarget.begin(), vTarget.end(), print01()); cout << endl;\n\t\n}\n\n//将容器1和容器2中的元素相加放入到第三个容器中\nstruct transformTest02{\n\tint operator()(int v1,int v2){\n\t\treturn v1 + v2;\n\t}\n};\nvoid test02(){\n\n\tvector vSource1;\n\tvector vSource2;\n\tfor (int i = 0; i < 10; i++){\n\t\tvSource1.push_back(i + 1);\t\n\t}\n\n\t//目标容器\n\tvector vTarget;\n\t//给vTarget开辟空间\n\tvTarget.resize(vSource1.size());\n\ttransform(vSource1.begin(), vSource1.end(), vSource2.begin(),vTarget.begin(), transformTest02());\n\t//打印\n\tfor_each(vTarget.begin(), vTarget.end(), print01()); cout << endl;\n}]]>

4.4 常用查找算法

 

/*

    find算法 查找元素

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param value 查找的元素

    @return 返回查找元素的位置

*/

find(iterator beg, iterator end, value)

/*

    find_if算法 条件查找

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param  callback 回调函数或者谓词(返回bool类型的函数对象)

    @return bool 查找返回true 否则false

*/

find_if(iterator beg, iterator end, _callback);


/*

    adjacent_find算法 查找相邻重复元素

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param  _callback 回调函数或者谓词(返回bool类型的函数对象)

    @return 返回相邻元素的第一个位置的迭代器

*/

adjacent_find(iterator beg, iterator end, _callback);

/*

    binary_search算法 二分查找法

    注意: 在无序序列中不可用

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param value 查找的元素

    @return bool 查找返回true 否则false

*/

bool binary_search(iterator beg, iterator end, value);

/*

    count算法 统计元素出现次数

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param  value回调函数或者谓词(返回bool类型的函数对象)

    @return int返回元素个数

*/

count(iterator beg, iterator end, value);

/*

count_if算法 统计元素出现次数

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param  callback 回调函数或者谓词(返回bool类型的函数对象)

    @return int返回元素个数

*/

count_if(iterator beg, iterator end, _callback);

 

4.5 常用排序算法

/*

    merge算法 容器元素合并,并存储到另一容器中

    注意:两个容器必须是有序的

    @param beg1 容器1开始迭代器

    @param end1 容器1结束迭代器

    @param beg2 容器2开始迭代器

    @param end2 容器2结束迭代器

    @param dest  目标容器开始迭代器

*/

merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)

/*

    sort算法 容器元素排序

    @param beg 容器1开始迭代器

    @param end 容器1结束迭代器

    @param _callback 回调函数或者谓词(返回bool类型的函数对象)

*/

sort(iterator beg, iterator end, _callback)

/*

    random_shuffle算法 对指定范围内的元素随机调整次序

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

*/

random_shuffle(iterator beg, iterator end)

/*

    reverse算法 反转指定范围的元素

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

*/

reverse(iterator beg, iterator end)

 

 

4.6 常用拷贝和替换算法

/*

    copy算法 将容器内指定范围的元素拷贝到另一容器中

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param dest 目标起始迭代器

*/

copy(iterator beg, iterator end, iterator dest)

/*

    replace算法 将容器内指定范围的旧元素修改为新元素

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param oldvalue 旧元素

    @param oldvalue 新元素

*/

replace(iterator beg, iterator end, oldvalue, newvalue)

/*

    replace_if算法 将容器内指定范围满足条件的元素替换为新元素

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param callback函数回调或者谓词(返回Bool类型的函数对象)

    @param oldvalue 新元素

*/

replace_if(iterator beg, iterator end, _callback, newvalue)

/*

    swap算法 互换两个容器的元素

    @param c1容器1

    @param c2容器2

*/

swap(container c1, container c2)

 

4.7 常用算数生成算法

/*

    accumulate算法 计算容器元素累计总和

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param value累加值

*/

accumulate(iterator beg, iterator end, value)

/*

    fill算法 向容器中添加元素

    @param beg 容器开始迭代器

    @param end 容器结束迭代器

    @param value t填充元素

*/

fill(iterator beg, iterator end, value)


 

4.8 常用集合算法

/*

    set_intersection算法 求两个set集合的交集

    注意:两个集合必须是有序序列

    @param beg1 容器1开始迭代器

    @param end1 容器1结束迭代器

    @param beg2 容器2开始迭代器

    @param end2 容器2结束迭代器

    @param dest  目标容器开始迭代器

    @return 目标容器的最后一个元素的迭代器地址

*/

set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)

/*

    set_union算法 求两个set集合的并集

    注意:两个集合必须是有序序列

    @param beg1 容器1开始迭代器

    @param end1 容器1结束迭代器

    @param beg2 容器2开始迭代器

    @param end2 容器2结束迭代器

    @param dest  目标容器开始迭代器

    @return 目标容器的最后一个元素的迭代器地址

*/

set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)

/*

    set_difference算法 求两个set集合的差集

    注意:两个集合必须是有序序列

    @param beg1 容器1开始迭代器

    @param end1 容器1结束迭代器

    @param beg2 容器2开始迭代器

    @param end2 容器2结束迭代器

    @param dest  目标容器开始迭代器

    @return 目标容器的最后一个元素的迭代器地址

*/

set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)


","representation":"storage","_expandable":{"content":"/rest/api/content/58954498"}},"_expandable":{"editor":"","view":"","export_view":"","styled_view":"","anonymous_export_view":""}},"extensions":{"position":"none"},"_links":{"webui":"/pages/viewpage.action?pageId=58954498","edit":"/pages/resumedraft.action?draftId=58954498","tinyui":"/x/ApODAw","collection":"/rest/api/content","base":"https://wiki.suncaper.net","context":"","self":"https://wiki.suncaper.net/rest/api/content/58954498"},"_expandable":{"container":"/rest/api/space/2CT","metadata":"","operations":"","children":"/rest/api/content/58954498/child","restrictions":"/rest/api/content/58954498/restriction/byOperation","history":"/rest/api/content/58954498/history","ancestors":"","descendants":"/rest/api/content/58954498/descendant","space":"/rest/api/space/2CT"}}