文章目录
- 一、函数对象
- 二、预定义的函数对象
- 三、算法函数
- 1.自己实现foreach算法
- 2.自己实现的findif算法
- 3.自己实现bsort算法
一、函数对象
STL提供了很多处理容器的函数模板,它们的设计是相同的,有以下特点:
1)用迭代器表示需要处理数据的区间。
2)返回迭代器放置处理数据的结果(如果有结果)。
3)接受一个函数对象参数(结构体模板),用于处理数据(如果需要)。
很多STL算法都使用函数对象,也叫函数符(functor),包括函数名、函数指针和仿函数。
函数符的概念:
1)生成器(generator):不用参数就可以调用的函数符。
2)一元函数(unary function):用一个参数可以调用的函数符。
3)二元函数(binary function):用两个参数可以调用的函数符。
改进的概念:
1)一元谓词(predicate):返回bool值的一元函数。
2)二元谓词(binary predicate):返回bool值的二元函数。
二、预定义的函数对象
STL定义了多个基本的函数符,用于支持STL的算法函数。
包含头文件:#include <functional>
三、算法函数
STL将算法函数分成四组:
1)非修改式序列操作:对区间中的每个元素进行操作,这些操作不修改容器的内容。
2)修改式序列操作:对区间中的每个元素进行操作,这些操作可以容器的内容(可以修改值,也可以修改排列顺序)。
3)排序和相关操作:包括多个排序函数和其它各种函数,如集合操作。
4)通用数字运算:包括将区间的内容累积、计算两个容器的内部乘积、计算小计、计算相邻对象差的函数。通常,这些都是数组的操作特性,因此vector是最有可能使用这些操作的容器。
前三组在头文件#include <algorithm>中,第四组专用于数值数据,在#include <numeric>中。
- eg:
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
template<typename T>
struct girl {
T m_yz; // 统计的颜值。
int m_count; // 符合条件的元素个数。
girl(const T yz) : m_yz(yz), m_count(0) {}
void operator()(const T& yz) {
if (yz==m_yz) m_count++;
}
};
int main()
{
vector<int> vv = { 1,3,2,4,1,2,3,1,4,3 }; // 1-极漂亮;2-漂亮;3-普通;4-歪瓜裂枣
//返回对象本身
girl<int> g=for_each(vv.begin(), vv.end(), girl<int>(1)); // 按颜值统计超女人数。
cout << "g.m_count=" << g.m_count << endl;
}
1.自己实现foreach算法
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
/*
void zsshow(int const& no) // 张三的个性化表白函数。
{
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
}
*/
template<typename T>
void zsshow(const T& no) // 张三的个性化表白函数。
{
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
}
/*
class czs // 张三的个性化表白仿函数。
{
public:
void operator()(int const& no) {
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
}
};
*/
template<typename T>
class czs // 张三的个性化表白仿函数。
{
public:
void operator()(const T& no) {
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
}
};
/*
void foreach(const vector<int>::iterator first, const vector<int>::iterator last)
{
for (auto it = first; it != last; it++)
cout << "亲爱的" << *it << "号:我是一只傻傻鸟。\n";
}
void foreach(const vector<int>::iterator first, const vector<int>::iterator last, void(*pfnc)(int const&))
{
for (auto it = first; it != last; it++)
pfnc(*it);
}
void foreach(const vector<int>::iterator first, const vector<int>::iterator last, czs pfnc)
{
for (auto it = first; it != last; it++)
pfnc(*it);
}
*/
//这里模板的思想是传迭代器,若对象进行值传递或者引用传递,则只是支持某种类型的对象
template<typename T1, typename T2>
void foreach(const T1 first, const T1 last, T2 pfun)
{
for (auto it = first; it != last; it++)
pfun(*it); // 以超女编号为实参调用类的operator()函数。
}
int main()
{
vector<int> bh = { 5,8,2,6,9,3,1,7 }; // 存放超女编号的容器。
//list<string> bh = { "05","08","02","06","09","03","01","07" }; // 存放超女编号的容器。
// 写一个函数,在函数中遍历容器,向超女表白,表白的方法可自定义。
foreach(bh.begin(), bh.end(), zsshow<int>); // 第三个参数是模板函数。
foreach(bh.begin(), bh.end(), czs<int>()); // 第三个参数是仿函数。
}
2.自己实现的findif算法
- eg1:
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
template<typename T>
bool zsshow(const T& no,const T & in_no) // 张三的个性化表白函数。
{
if (no != in_no) return false;
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
return true;
}
template<typename T>
class czs // 张三的个性化表白仿函数。
{
public:
bool operator()(const T& no, const T& in_no) {
if (no != in_no) return false;
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
return true;
}
};
template<typename T1, typename T2, typename T3>
T1 findif(const T1 first, const T1 last, T2 pfun,T3 in_no)
{
for (auto it = first; it != last; it++)
if (pfun(*it, in_no) ==true) return it; // 用迭代器调用函数对象。
return last;
}
int main()
{
vector<int> bh = { 5,8,2,6,9,33,1,7 }; // 存放超女编号的容器。
//list<string> bh = { "05","08","02","06","09","03","01","07" }; // 存放超女编号的容器。
auto it1=findif(bh.begin(), bh.end(), zsshow<int>,2); // 第三个参数是模板函数。
if (it1 == bh.end()) cout << "查找失败。\n";
else cout << "查找成功:" << *it1 << endl;
auto it2=findif(bh.begin(), bh.end(), czs<int>(),33); // 第三个参数是仿函数。
if (it2 == bh.end()) cout << "查找失败。\n";
else cout << "查找成功:" << *it2 << endl;
}
- eg2:更好的方式
#include <iostream>
#include <vector>
#include <list>
#include <algorithm> // STL算法函数头文件。
using namespace std;
template<typename T>
bool zsshow(const T& no) // 张三的个性化表白函数。
{
if (no != 3) return false;
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
return true;
}
template<typename T>
class czs // 张三的个性化表白仿函数。
{
public:
T m_no; // 存放张三喜欢的超女编号。
czs(const T& no) : m_no(no) {} // 构造函数的参数是张三喜欢的超女编号。
bool operator()(const T& no) {
if (no != m_no) return false;
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
return true;
}
};
template<typename T1, typename T2>
T1 findif(const T1 first, const T1 last, T2 pfun)
{
for (auto it = first; it != last; it++)
if (pfun(*it) ==true) return it; // 用迭代器调用函数对象。
return last;
}
int main()
{
vector<int> bh = { 5,8,2,6,9,33,1,7 }; // 存放超女编号的容器。
//list<string> bh = { "05","08","02","06","09","03","01","07" }; // 存放超女编号的容器。
auto it1=find_if(bh.begin(), bh.end(), zsshow<int>); // 第三个参数是模板函数。
if (it1 == bh.end()) cout << "查找失败。\n";
else cout << "查找成功:" << *it1 << endl;
auto it2=find_if(bh.begin(), bh.end(), czs<int>(8)); // 第三个参数是仿函数。
if (it2 == bh.end()) cout << "查找失败。\n";
else cout << "查找成功:" << *it2 << endl;
}
3.自己实现bsort算法
#include <iostream>
#include <vector>
#include <list>
#include <algorithm> // STL算法函数。
#include <functional> // STL仿函数。
using namespace std;
template<typename T>
bool compasc(const T& left, const T& right) { // 普通函数,用于升序。
return left < right;
}
template<typename T>
struct _less
{
bool operator()(const T& left, const T& right) { // 仿函数,用于升序。
return left < right;
}
};
template<typename T>
bool compdesc(const T& left, const T& right) { // 普通函数,用于降序。
return left > right;
}
template<typename T>
class _greater
{
public:
bool operator()(const T& left, const T& right) { // 仿函数,用于降序。
return left > right;
}
};
template<typename T, typename compare>
void bsort(const T first, const T last, compare comp) // 冒泡排序。
{
while(true)
{
bool bswap = false; // 本轮遍历已交换过元素的标识,true-交换过,false-未交换过。
for (auto it = first; ; )
{
auto left = it; // 左边的元素。
it++;
auto right = it; // 右边的元素。
if (right == last) break; // 表示it1已经是最后一个元素了。
//if (*left > *right) // 如果左边的元素比右边大,交换它们的值。
//if (*left < *right) // 如果左边的元素比右边小,交换它们的值。
// 排序规则:如果comp()返回true,left排在前面(升序),否则right排在前面(降序)。
if (comp(*left, *right) == true) continue;
// 交换两个元素的值。
auto tmp = *right;
*right = *left;
*left = tmp;
bswap = true; // 一轮遍历已交换过元素的标识。
}
if (bswap == false) break; // 如果在for循环中不曾交换过元素,说明全部的元素已有序。
}
}
int main()
{
vector<int> bh = { 5,8,2,6,9,33,1,7 }; // 存放超女编号的容器。
//list<string> bh = { "05","08","02","06","09","03","01","07" }; // 存放超女编号的容器。
//bsort(bh.begin(), bh.end(),compasc<int>); // 普通函数(升序)。
//bsort(bh.begin(), bh.end(), compdesc<int>); // 普通函数(降序)。
//bsort(bh.begin(), bh.end(),_less<int>()); // 仿函数(升序)。
//bsort(bh.begin(), bh.end(), _greater<int>()); // 仿函数(降序)。
//bsort(bh.begin(), bh.end(), less<int>()); // STL提供的仿函数(升序)。
//bsort(bh.begin(), bh.end(), greater<int>()); // STL提供的仿函数(降序)。
//sort(bh.begin(), bh.end(),_less<int>()); // 仿函数(升序)。
sort(bh.begin(), bh.end(), _greater<int>()); // 仿函数(降序)。
for (auto val : bh)
cout << val << " ";
cout << endl;
}
- ref:从0基础系统化学习C++,不可能学不会