CppSTL(二)
OVERVIEW
- CppSTL(二)
- 一、函数对象
- 1.函数对象:
- (1)概述:
- (2)简单使用:
- 2.谓词:
- (1)一元谓词:
- (2)二元谓词:
- 3.内建函数对象:
- (1)算术仿函数:
- (2)关系仿函数:
- (3)逻辑仿函数:
- 二、STL常用算法
- 1.遍历for_each
- (1)for_each:
- (2)transform:
- 2.查找find
- (1)find:
- (2)find_if:
- (3)其他find&count:
- 3.排序sort
- (1)sort
- (2)random_shuffle
- (3)merge
- (4)reverse
- 4.拷贝&替换copy
- (1)copy:
- (2)replace:
- (3)replace_if:
- (4)swap:
- 5.算术生成
- (1)accumulate:
- (2)fill:
- 6.集合算法
一、函数对象
1.函数对象:
(1)概述:
- 函数对象是指,重载函数调用操作符的类。
- 函数对象使用重载的
()
时,行为类似函数调用(仿函数)。
注意:函数对象(仿函数)的本质是一个类,而不是函数。
(2)简单使用:
函数对象特点:
- 函数对象在使用时,可以像普通函数一样具有传递参数和返回值。
- 函数对象与普通函数不同,函数对象可以有自己的状态。
- 函数对象可以作为参数传递。
#include<iostream>
using namespace std;
//1.函数对象在使用时,可以像普通函数一样有参数与返回值
class MyAdd{
public:
int operator()(int num1, int num2){
return num1 + num2;
}
};
void test01(){
MyAdd myAdd;
cout << myAdd(10, 10) << endl;
}
//2.函数对象可以拥有自己的状态
class MyPrint{
public:
MyPrint(){this->count = 0;}
void operator()(string str){
cout << str << endl;
}
int count;//记录内部状态
};
void test02(){
MyPrint myPrint;
myPrint("hello world");
cout << "myPrint调用的次数为:" << myPrint.count << endl;
}
//3.函数对象可以作为参数传递
void doPrint(MyPrint &mp, string str){
mp(str);
}
void test03(){
MyPrint myPrint;
doPrint(myPrint, "This is a test for the 3th Principle.");
}
int main(){
test01();
test02();
test03();
system("pause");
return 0;
}
仿函数的写法非常灵活,可以作为参数进行传递,没有固定写法。
2.谓词:
返回bool类型的仿函数被称为谓词,如果operator()接收一个参数则被称为做一元谓词,接收两个谓词则被称为二元谓词。
(1)一元谓词:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class GreaterFive{
public:
bool operator()(int val){return val > 5;}
};
int main(){
vector<int> v;
for(int i = 0; i < 10; ++i){
v.push_back(i);
}
//查找容器中是否有大于5的数字,返回一个迭代器
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if(it == v.end()){
cout << "未找到" << endl;
}else{
cout << "找到了大于5的数字:" << *it << endl;
}
system("pause");
return 0;
}
(2)二元谓词:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class MyCompare{
public:
bool operator()(int num1, int num2){
return num1 > num2;
}
};
void printVector(vector<int> &v){
for(vector<int>::iterator it = v.begin(); it != v.end(); ++it){
cout << *it << " ";
}
cout << endl;
}
int main(){
vector<int> v;
v.push_back(40);
v.push_back(30);
v.push_back(10);
v.push_back(50);
v.push_back(20);
//1.使用sort默认排序算法进行排序
sort(v.begin(), v.end());
printVector(v);
//2.使用函数对象改变算法排序规则
sort(v.begin(), v.end(), MyCompare());
printVector(v);
system("pause");
return 0;
}
3.内建函数对象:
内建函数对象指的c++STL中已经提供了的一些仿函数,
这些仿函数所产生的对象、用法和一般函数完全相同,使用内建函数对象时需要提前引入头文件#include<functional>
(1)算术仿函数:
算术仿函数实现了四则算术运算,其中negate是一元运算,其他都是二元运算。
算术仿函数原型 | 说明 |
---|---|
template<typename T> T plus<T> | 加法 |
template<typename T> T minus<T> | 减法 |
template<typename T> T multiplies<T> | 乘法 |
template<typename T> T divides<T> | 除法 |
template<typename T> T modulus<T> | 取模 |
template<typename T> T negate<T> | 取反 |
#include<iostream>
#include<functional>
using namespace std;
void test01(){
//negate取反仿函数(一元法仿函数取)
negate<int> n;
cout << "取反仿函数:" << n(50) << endl;
//plus加法仿函数(二元仿函数)
plus<int> p;
cout << "加法仿函数:" << p(10, 20) << endl;
}
int main(){
test01();
system("pause");
return 0;
}
(2)关系仿函数:
关系仿函数实现了关系比较。
关系仿函数原型 | 说明 |
---|---|
template<typename T> bool equal_to<T> | == |
template<typename T> bool not_equal_to<T> | != |
template<typename T> bool greater<T> | > |
template<typename T> bool greater_equal<T> | >= |
template<typename T> bool less<T> | < |
template<typename T> bool less_equal<T> | <= |
#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;
class MyConpare{
public:
bool operator()(int num1 ,int num2){
return num1 > num2;
}
};
void printVector(vector<int> &v){
for(vector<int>::iterator it = v.begin(); it != v.end(); ++it){
cout << *it << " ";
}
cout << endl;
}
void test01(){
//1.自主实现仿函数,实现sort降序排序
vector<int> v1;
v1.push_back(40);
v1.push_back(10);
v1.push_back(50);
v1.push_back(30);
v1.push_back(20);
sort(v1.begin(), v1.end(), MyConpare());
printVector(v1);
//2.使用内建函数对象(仿函数),实现sort降序排序
vector<int> v2;
v2.push_back(80);
v2.push_back(60);
v2.push_back(100);
v2.push_back(90);
v2.push_back(70);
sort(v2.begin(), v2.end(), greater<int>());
printVector(v2);
}
int main(){
test01();
system("pause");
return 0;
}
(3)逻辑仿函数:
逻辑仿函数实现了逻辑运算。
逻辑仿函数原型 | 说明 |
---|---|
template<typename T> bool logical_and<T> | 逻辑与 |
template<typename T> bool logical_or<T> | 逻辑或 |
template<typename T> bool logical_not<T> | 逻辑非 |
#include<iostream>
#include<vector>
#include<algorithm>
#include<functional>
using namespace std;
void printVector(vector<bool> &v){
for(vector<bool>::iterator it = v.begin(); it != v.end(); ++it){
cout << *it << " ";
}
cout << endl;
}
void test01(){
vector<bool> v1;
v1.push_back(true);
v1.push_back(false);
v1.push_back(false);
v1.push_back(true);
v1.push_back(true);
printVector(v1);
//利用逻辑非操作,将容器v中的元素搬运到v2中(并执行取反操作)
vector<bool> v2;
v2.resize(v1.size());//必须提前开辟空间否则无法搬运
transform(v1.begin(), v1.end(), v2.begin(), logical_not<bool>());
printVector(v2);
}
int main(){
test01();
system("pause");
return 0;
}
二、STL常用算法
STL中的算法主要是由头文件<algorithm>
、<functional>
、<numeric>
组成
- algorithm是所有STL头文件中最大的一个,范围涉及到复制、交换、修改、查找、比较、遍历等操作
- numeric体积很小,只包括几个在序列上进行简单数学运算的模板函数
- functional定义了一些模板类用于声明函数对象
1.遍历for_each
常用的遍历算法包括for_each遍历容器与transform搬运容器元素到另一个容器中。
(1)for_each:
- 函数原型:
for_each(iterator beg, iterator end, _func);
beg开始迭代器、end结束迭代器、_func函数or函数对象
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//普通函数
void print01(int num){
cout << num << " ";
}
//仿函数
class print02{
public:
void operator()(int num){
cout << num << " ";
}
};
int main(){
vector<int> v;
for(int i = 0; i < 10; ++i) v.push_back(i);
for_each(v.begin(), v.end(), print01); cout << endl;//普通函数参数为函数名
for_each(v.begin(), v.end(), print02()); cout << endl;//仿函数参数为函数对象
system("pause");
return 0;
}
(2)transform:
- 函数原型:
transform(iterator beg1, iterator end1, iterator2, _func);
beg1源容器开始迭代器、end1源容器结束迭代器、beg2目标容器开始迭代器、_func函数or函数对象
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Transform{
public:
int operator()(int val){
return val + 1000;//逻辑操作
}
};
class Print{
public:
void operator()(int val){
cout << val << " ";
}
};
int main(){
vector<int> v;
for(int i = 0; i < 10; ++i) v.push_back(i);
vector<int> vTarget;
vTarget.resize(v.size());//需要先指定target容器大小
transform(v.begin(), v.end(), vTarget.begin(), Transform());
for_each(v.begin(), v.end(), Print());cout << endl;
for_each(vTarget.begin(), vTarget.end(), Print());cout << endl;
system("pause");
return 0;
}
2.查找find
(1)find:
find(iterator beg, iterator end, value)
:查找指定元素(返回指定元素迭代器,未找到则返回迭代器end)
beg开始迭代器、end结束迭代器、value查找元素
查找内置数据类型:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void test01(){
vector<int> v;
for(int i = 0; i < 10; ++i) v.push_back(i);
vector<int>::iterator it = find(v.begin(), v.end(), 5);
if(it == v.end()){
cout << "没有找到元素" << endl;
}else{
cout << "找到元素:" << *it << endl;
}
}
int main(){
test01();
system("pause");
return 0;
}
查找自定义数据类型:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Person{
public:
Person(string n, int a){
this->name = n;
this->age = a;
}
//重载==使底层find知道如何对比person数据类型
bool operator==(const Person &p){
if(this->name == p.name && this->age == p.age){
return true;
}else{
return false;
}
}
string name;
int age;
};
void test02(){
vector<Person> v;
Person p1("lch", 18);
Person p2("uio", 20);
Person p3("rty", 15);
Person p4("bnm", 25);
Person p5("cvb", 29);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
vector<Person>::iterator it = find(v.begin(), v.end(), p2);
if(it == v.end()){
cout << "没有找到元素" << endl;
}else{
cout << "找到元素 姓名:" << it->name << "\t年龄:" << it->age << endl;
}
}
int main(){
test02();
system("pause");
return 0;
}
注意:find可以在指定的容器中查询value元素,但其返回值是一个迭代器。
(2)find_if:
find_if(iterator beg, iterator end, _Pred)
:查找指定元素(返回指定元素迭代器,未找到则返回迭代器end)
beg开始迭代器、end结束迭代器、_Pred函数或谓词(返回bool类型的仿函数)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//1.查找内置数据类型
class GreaterFive{
public:
bool operator()(int val){
return val > 5;//当val>5时返回true
}
};
void test01(){
vector<int> v;
for(int i = 0; i < 10; ++i) v.push_back(i);
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
if(it == v.end()){
cout << "没有找到元素" << endl;
}else{
cout << "找到元素:" << *it << endl;
}
}
//2.查找自定义数据类型
class Person{
public:
Person(string n, int a){
this->name = n;
this->age = a;
}
//不需要重载==使底层find知道如何对比person数据类型
string name;
int age;
};
class GreaterTwenty{
public:
bool operator()(Person &p){
return p.age > 20;
}
};
void test02(){
vector<Person> v;
Person p1("lch", 18);
Person p2("uio", 20);
Person p3("rty", 15);
Person p4("bnm", 25);
Person p5("cvb", 29);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
vector<Person>::iterator it = find_if(v.begin(), v.end(), GreaterTwenty());
if(it == v.end()){
cout << "没有找到元素" << endl;
}else{
cout << "找到元素 姓名:" << it->name << "\t年龄:" << it->age << endl;
}
}
int main(){
test01();
test02();
system("pause");
return 0;
}
注意:find与find_if的一个区别,在查找自定义数据类型时find需要重载
==
而find_if不需要
(3)其他find&count:
其他find | 说明 |
---|---|
adjacent_find(iterator beg, iterator end) | 查找相邻重复元素,返回相邻元素的第一个位置的迭代器 |
bool binary_search(iterator beg, iterator end, value) | 查找指定元素,查到返回true否则false |
注意:binary_search在无序序列中无法使用,只能在有序序列中才能进行二分查找
count统计 | 说明 |
---|---|
count(iterator beg,iterator end, value) | 与find查找类似,在查找时都需要对== 进行重载 |
count_if(iterator beg,iterator end, _Pred) | 与find_if查找类似,照条件统计元素个数 |
3.排序sort
(1)sort
sort(iterator beg, iterator end, _Pred);
按值查找元素,找到返回指定位置迭代器,否则返回结束迭代器位置
(2)random_shuffle
random_shuffle(iterator beg, iterator end);
指定范围内的元素随机调整次序
#include<iostream>
#include<vector>
#include<algorithm>
#include<ctime>
using namespace std;
void myPrint(int val){
cout << val << " ";
}
int main(){
srand((unsigned int)time(NULL));//按照系统时间生成种子
vector<int> v;
for(int i = 0; i < 10; ++i){
v.push_back(i);
}
random_shuffle(v.begin(), v.end());
for_each(v.begin(), v.end(), myPrint);
cout << endl;
system("pause");
return 0;
}
注意:使用random_shuffle时,记得加上随机数种子保证随机洗牌
(3)merge
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest)
容器合并后存储到另一容器中
beg1、end1容器1的开始和结束迭代器,beg2、end2容器2的开始和结束迭代器,dest目标容器开始迭代器
注意:进行容器元素合并的两个容器必须是有序的
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void myPrint(int val){
cout << val << " ";
}
int main(){
vector<int> v1;
vector<int> v2;
for(int i = 0; i < 10; ++i){
v1.push_back(i);
v2.push_back(i + 1);
}
for_each(v1.begin(), v1.end(), myPrint);
cout << endl;
for_each(v2.begin(), v2.end(), myPrint);
cout << endl;
vector<int> vTarget;
vTarget.resize(v1.size() + v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), vTarget.end(), myPrint);
cout << endl;
system("pause");
return 0;
}
注意:
- merge合并的两个容器必须是有序序列,且序列一致
- 目标容器在使用前必须提前开辟内存空间
(4)reverse
reverse(iterator beg, iterator end)
反转指定范围内的元素
4.拷贝&替换copy
(1)copy:
copy(iterator beg, iterator end, iterator dest)
:将容器内指定范围的元素拷贝到另一容器中
注意:利用copy算法在拷贝时,目标容器需要提前开辟空间
(2)replace:
replace(iterator beg, iterator end, oldvalue, newvalue)
:将容器内指定范围的旧元素,修改为新元素。
(3)replace_if:
replace_if(iterator beg, iterator end, _pred, newvalue)
:将容器内指定范围、满足条件的旧元素,修改为新元素。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Print {
public:
void operator()(int val) {
cout << val << " ";
}
};
//replace_if按条件查找,可以利用仿函数进行灵活筛选
class Greater20 {
public:
bool operator() (int val) {
return val >= 20;
}
};
int main() {
vector<int> v1;
v1.push_back(10);
v1.push_back(50);
v1.push_back(40);
v1.push_back(20);
v1.push_back(30);
cout << "before : ";
for_each(v1.begin(), v1.end(), Print());
cout << endl;
replace_if(v1.begin(), v1.end(), Greater20(), 999);
cout << "after : ";
for_each(v1.begin(), v1.end(), Print());
cout << endl;
system("pause");
return 0;
}
(4)swap:
swap(container c1, container c2)
:互换两个容器的元素(同种容器)
5.算术生成
算术生成算法属于小型算法,使用时包含的头文件为#include<numeric>
(1)accumulate:
accumulate(iterator beg, iterator end, value)
:计算指定区间内容器元素累计总和,
(2)fill:
fill(iterator beg, iterator end, value)
:向指定区间内容器中填充元素,
6.集合算法
集合算法 | 说明 |
---|---|
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest) | 求交集 |
set_union | 求并集 |
set_difference | 求差集 |
注:两个容器必须是有序序列
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val) {
cout << val << " ";
}
//求交集
void test01(vector<int> v1, vector<int> v2) {
//目标容器需要提前开辟空间
vector<int> v3;
v3.resize(min(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); cout << endl;
}
//求并集
void test02(vector<int> v1, vector<int> v2) {
//目标容器需要提前开辟空间
vector<int> v3;
v3.resize(v1.size() + v2.size());
//获取交集
vector<int>::iterator itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
//遍历结果
for_each(v3.begin(), itEnd, myPrint); cout << endl;
}
//求差集
void test03(vector<int> v1, vector<int> v2) {
//目标容器需要提前开辟空间
vector<int> v3;
v3.resize(max(v1.size(), v2.size()));
//获取交集
vector<int>::iterator itEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
//遍历结果
for_each(v3.begin(), itEnd, myPrint); cout << endl;
}
int main() {
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
v2.push_back(i + 5);
}
test01(v1, v2);
test02(v1, v2);
test03(v1, v2);
system("pause");
return 0;
}