谓词
先理解一下什么是谓词
仿函数的返回值类型是bool数据类型,称为谓词,
其中仿函数的形参有一个就是一元谓词,两个就是二元谓词
代码演示:
class GreaterFive
{
public:
bool operator()(int val) // 形参有一个就是一元谓词,两个就是二元
{
return val > 5;
}
};
void demo01()
{
vector<int> v;
for (int i = 0; i < 10; ++i) {
v.push_back(i);
}
// GreaterFive() 匿名函数对象
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if (it == v.end()) {
cout << "没有大于5的数" << endl;
}
else {
cout << *it << endl;
}
}
class MySort
{
public:
// 重写()的返回值是bool类型称为谓词
bool operator()(int a, int b) // 二元谓词
{
return a > b;
}
};
void demo02()
{
vector<int> v;
v.push_back(1);
v.push_back(3);
v.push_back(5);
v.push_back(2);
v.push_back(4);
sort(v.begin(), v.end(), MySort()); // 降序
}
函数对象
函数对象就是仿函数
1、函数对象在使用时可以有参数也可以有返回值
2、函数对象超出普通对象的概念,函数对象可以有自己的状态
3、函数对象可以做参数传递
代码演示:
// 1、函数对象在使用时可以有参数也可以有返回值
class MyAdd
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
// 2、函数对象超出普通对象的概念,函数对象可以有自己的状态
class MyPrint
{
public:
MyPrint()
{
this->count = 0;
}
void operator()(string test)
{
cout << test << endl;
this->count++; // 可以通过count来记录仿函数被调用的次数
}
int count;
};
void demo01()
{
MyAdd ma;
cout << ma(10, 11) << endl; // 函数对象
}
void demo02()
{
MyPrint mp;
mp("123");
mp("123");
mp("123");
mp("123");
cout << "调用了" << mp.count << "次" << endl; // 函数对象自己的状态
}
// 3、函数对象可以做参数传递
void demo03(MyPrint& sp)
{
sp("123");
}
void test()
{
MyPrint mp;
demo03(mp);
}
内建函数
内建仿函数(STL已经写好的仿函数,需要引入#include<functional>头文件
代码演示:算数仿函数
1、negate 一元仿函数 取反仿函数
2、plus 二元反函数 算数仿函数
使用内建函数需要引入<functional>头文件
void demo01()
{
negate<int> n; // 创建函数对象
cout << n(50) << endl; // 对50取反 为-50
}
void demo02()
{
plus<int> p;
cout << p(10, 20) << endl; // 二元仿函数,相加
}
关系仿函数
1、greater 大于仿函数
2、equal_to 等于仿函数
3、not_equal_to 不等于仿函数
4、greater_equal 大于等于仿函数
5、less 小于仿函数
6、less_equal 小于等于仿函数
void demo03()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(50);
v.push_back(30);
v.push_back(40);
sort(v.begin(), v.end(), greater<int>()); // 降序
// 其他关系仿函数用途类似,都是当作谓词处理
}
代码演示:逻辑仿函数
1、logical_and 与
2、logical_or 或
3、logical_not 非
void demo04()
{
vector<bool>v;
v.push_back(true);
v.push_back(false);
v.push_back(true);
// 利用取反仿函数 搬运到另一个容器在搬运期间取反
vector<bool> v2;
v2.resize(v.size()); // 使用transform搬运前必须使其空间足够
transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
}
STL常用标准算法
STL的标准算法都需要引入<algorithm>头文件
还有<numeric> // 小型的算法库,只包含几个序列上进行简单数学运算的算法
1、遍历算法
1、for_each : 遍历
2、transform :搬运
void print01(int val)
{
cout << val << " ";
}
class print02
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void demo01()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(30);
v.push_back(20);
for_each(v.begin(), v.end(), print01); // 调用全局函数作为遍历操作
cout << endl;
for_each(v.begin(), v.end(), print02()); // 调用仿函数作为遍历操作
}
int trans01(int val)
{
return val; // 不操作直接返回
}
class trans02
{
public:
int operator()(int val) {
return val;
}
};
// 搬运
void demo02()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(30);
v.push_back(20);
vector<int> v2;
v2.resize(v.size()); // 搬运目标容器必须有足够的空间
transform(v.begin(), v.end(), v2.begin(), trans01); // 调用全局函数作为搬运时操作
transform(v.begin(), v.end(), v2.begin(), trans02()); // 调用仿函数作为搬运时操作
}
2、查找算法
1、find:按值查找
2、find_if:条件查找
3、adjacent_find:查找相邻元素一样的情况
4、binary_search:按值二分查找
class Myif
{
public:
bool operator()(int val) {
return val > 20;
}
};
void demo03()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(30);
v.push_back(40);
vector<int>::iterator it = find(v.begin(), v.end(), 10); // 按值查找
// 按谓词条件范围查找,返回第一个符合条件的迭代器
it = find_if(v.begin(), v.end(), Myif());
it = adjacent_find(v.begin(), v.end()); // 查找相邻一样的元素,返回第一个元素的迭代器
// 二分查找指定元素,查到返回true,否则返回false,容器内必须有序
bool exists = binary_search(v.begin(), v.end(), 20);
}
3、统计算法
1、count:统计指定元素个数
2、count_if:按条件统计元素个数
class Myif
{
public:
bool operator()(int val) {
return val > 20;
}
};
void demo04()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(30);
v.push_back(40);
int sum = count(v.begin(), v.end(), 30); // 统计指定元素个数
sum = count_if(v.begin(), v.end(), Myif()); // 按范围统计
}
4、排序算法
1、sort:有序排序
2、random_shuffle:洗牌
3、merge:合并两个有序的容器,将结果输出到新的容器依然有序
4、reverse:逆序
class MySort
{
public:
bool operator()(int a, int b) {
return a > b;
}
};
void demo05()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(30);
v.push_back(40);
sort(v.begin(), v.end(), MySort()); // 第三参数不传默认升序
// 随机打乱 洗牌算法
srand((unsigned int)time(NULL)); // 生成随机种子,使得每次随机值都不一样
random_shuffle(v.begin(), v.end()); // 随机打乱容器中的元素顺序,用于洗牌
// 将两个有序序列合并到另一个容器中,整体依然有序
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(30);
v1.push_back(40);
vector<int> v2;
v2.push_back(10);
v2.push_back(20);
v2.push_back(30);
v2.push_back(30);
v2.push_back(40);
vector<int> v3;
v3.reserve(v1.size() + v2.size()); // 必须有足够的空间
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
// 将容器中的元素逆序
reverse(v3.begin(), v3.end()); // 将指定区间逆序
}
5、常用拷贝和替换
1、copy:将指定区间内容拷贝到指定容器中
2、copy_if:指定区间按谓词条件拷贝到目标容器中
3、replace:按值替换
4、replace_if:按谓词条件替换
void demo06()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(30);
v1.push_back(40);
vector<int> v2;
v2.push_back(10);
v2.push_back(20);
v2.push_back(30);
v2.push_back(30);
v2.push_back(40);
vector<int> v3;
v3.reserve(v1.size());
copy(v1.begin(), v1.end(), v3.begin());// 将指定区间内容拷贝到指定容器中
// 指定区间按谓词条件拷贝到目标容器中
copy_if(v1.begin(), v1.end(), v3.begin(), Myif());
// 替换
replace(v2.begin(), v2.end(), 20, 100); // 将指定区间的所有20换成100
// 将指定区间的元素按谓词条件全部替换成指定值
replace_if(v2.begin(), v2.end(), Myif(), 200);
}
6、互换
void demo07()
{
vector<int> v1;
vector<int> v2;
v1.swap(v2); // 容器自带的
swap(v1, v2); // 标准算法将两容器互换
// 两种方式效果一样
}
7、算数生成算法 在头文件<numeric>中
1、accumulate:按初始值累加
2、fill:后期重新填充
void demo08()
{
vector<int> v1;
for (int i = 1; i < 101; ++i) {
v1.push_back(i);
}
// 第三个参数为累加的初始值,返回指定区间元素累加并加初始值的总和
int total = accumulate(v1.begin(), v1.end(), 0);// 从0开始累加容器中所有元素
cout << total << endl; // 打印5050
total = accumulate(v1.begin(), v1.end(), 2);
cout << total << endl; // 打印5052
}
void demo09()
{
vector<int> v1;
v1.resize(10);
// 后期重新填充
fill(v1.begin(), v1.end(), 100); // 将指定区间填充为指定值
}
8、集合算法
1、set_intersection:求交集
2、set_union:求并集
3、set_difference:求差集
void myPrint(int val)
{
cout << val << " ";
}
// 集合算法
void demo10()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
vector<int> v2;
v2.push_back(20);
v1.push_back(30);
v1.push_back(40);
vector<int> v3;
v3.resize(v1.size()+v2.size()); // 目标容器空间必须足够大
// 求交集, 返回目标容器交集最后一个元素的迭代器
vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for_each(v3.begin(), itEnd, myPrint);// 这里用itEnd,如果用v3.end()会打印多余的数据
v3.clear();
// 求并集,返回目标容器并集最后一个元素的迭代器
itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for_each(v3.begin(), itEnd, myPrint);
v3.clear();
// 求差集,返回目标容器差集最后一个元素的迭代器
// v2-v1=v1中不是交集的部分,v1-v2=v2中不是交集的部分
itEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for_each(v3.begin(), itEnd, myPrint);
// 注意:被求集合必须有序
}