算法基础
1.函数对象
1.1 概念
函数调用操作符,也就是小括号(),重载了此操作符的类,称之为函数对象,函数对象是行为类似于函数的对象,也叫仿函数(functor),函数对象使类可以像函数那样调用
注意:
- 函数对象是个类,不是一个函数
- 函数对象重载了函数调用操作符,使类可以像函数那样调用
在一个类中,当我们重载()操作符时,若重载的operator()需要一个参数,则称之为一元仿函数,若重载的operator()需要两个参数,则称之为二元仿函数
#include <iostream>
#include <map>
using namespace std;
class MyPrint {
public:
int num;
MyPrint() {
num = 0;
}
void operator()(int num) {
this->num = num;
}
};
int main() {
MyPrint mp;
mp(1000);
cout << mp.num << endl;
return 0;
}1.2 谓语
如果一个仿函数中重载()的函数返回类型为bool类型,那么这样的仿函数就是谓语,也叫谓词
1.3 内置仿函数
STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。使用内建函数对象,需要引入头文件#include <functional>。
1.3.1 算数类
除了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> // 取反仿函数使用实例
#include <iostream>
#include <functional>
using namespace std;
int main() {
plus<int> p;
cout << p(10, 20)<< endl; // 30
minus<int> min;
cout << min(10,4) << endl; // 6
multiplies<int> multip;
cout << multip(10,5) << endl; // 50
divides<int> d;
cout << d(10, 5) << endl; // 2
modulus<int> mo;
cout << mo(10, 3) << endl; // 1
negate<int> ne;
cout << ne(10) << endl; // -10
return 0;
}1.3.2 关系运算类
每一种都是二元运算。
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> // 小于等于使用实例
#include <iostream>
#include <functional>
using namespace std;
int main() {
equal_to<int> equal;
cout << equal(10, 10) << endl; // 1
cout << equal(10, 9) << endl; // 0
not_equal_to<int> not_equal;
cout << not_equal(10, 10) << endl; // 0
cout << not_equal(10, 9) << endl; // 1
greater<int> greater;
cout << greater(9, 10) << endl; // 0
cout << greater(10, 10) << endl; // 0
cout << greater(10, 9) << endl; // 1
greater_equal<int> gequal;
cout << gequal(10, 10) << endl; // 1
cout << gequal(10, 9) << endl; // 1
less<int> less;
cout << less(10, 10) << endl; // 0
cout << less(9, 10) << endl; // 1
less_equal<int> less_e;
cout << less_e(10, 10) << endl; // 1
cout << less_e(9, 10) << endl; // 1
return 0;
}1.3.3 逻辑运算类
logical_not为一元运算,其余为二元运算
template<class T>bool logical_and<T> //逻辑与
template<class T>bool logical_or<T> //逻辑或
template<class T>bool logical_not<T> //逻辑非使用实例
#include <iostream>
#include <functional>
using namespace std;
int main() {
logical_and<int> la;
cout << la(10 < 9, 9 < 10) << endl; // 0
logical_or<int> lo;
cout << la(10 < 9, 9 < 10) << endl; // 1
logical_not<int> ln;
cout << ln(10 < 9) << endl; // 1
return 0;
}2.算法
算法主要是由头文件组成。 是所有STL头文件中最大的一个,其中常用的功能涉及到比较,交换,查找,遍历,复制,修改,反转,排序,合并等.. 体积很小,只包括在几个序列容器上进行的简单运算的模板函数。 定义了一些模板类,用以声明函数对象。
使用算法需要引入头文件algorithm
#include <algorithm>2.1 常用遍历算法
2.1.1 for_each()
/*
遍历算法遍历容器元素
@param beg开始选代器
@param end结束选代器
@param _ca11back 函数回调或者函数对象
@return 函数对象
*/
for_each(iterator beg,iterator end,_callback)使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class Print {
public:
void operator()(int i) {
cout << i << ",";
}
};
int main() {
vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };
for_each(v.begin(), v.end(), Print());
return 0;
}第三个参数也可以传一个函数的引用,注意不能加(),不然就变成了函数的调用
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void print(int i) {
cout << i << ",";
}
int main() {
vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };
for_each(v.begin(), v.end(), print);
return 0;
}2.1.2 transform()
transform算法将指定容器区间元素搬运到另一容器中 注意:transform不会给目标容器分配内存,所以需要我们提前分配好内存
/*
transform算法将指定容器区间元素搬运到另一容器中
注意:transform不会给目标容器分配内存,所以需要我们提前分配好内存
@param beg1 源容器开始迭代器
@param end1 源容器结束选代器
@param beg2 目标容器开始迭代器
@param_callback 回调函数或者函数对象
@return 返回目标容器选代器
**/
transform(iterator beg1, iterator end1, iterator beg2, _callback);
/*
将两个容器加工并拷贝到另一个容器
注意:transform不会给目标容器分配内存,所以需要我们提前分配好内存
@param beg1 第一个源容器开始迭代器
@param end1 第一个源容器结束选代器
@param beg2 第二个源容器开始迭代器
@param beg3 目标容器开始迭代器
@param_callback 回调函数或者函数对象
@return 返回目标容器选代器
**/
transform(iterator beg1, iterator end1, iterator beg2, iterator beg3, _callback);实现容器的拷贝
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class NumberOperator {
public:
int operator()(int i) {
return i;
}
};
void printVector(vector<int>& v) {
for (int ele : v) {
cout << ele << ",";
}
}
int main() {
vector<int> v1 = { 1,2,3,4,5,6,7,8,9,10 };
vector<int> v2;
v2.resize(v1.size());
// 把v1拷贝到v2
transform(v1.begin(), v1.end(), v2.begin(), NumberOperator());
printVector(v2); // { 1,2,3,4,5,6,7,8,9,10 };
return 0;
}拷贝过程中,将数据进行加工
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class NumberOperator {
public:
int operator()(int i) {
return i+100;
}
};
void printVector(vector<int>& v) {
for (int ele : v) {
cout << ele << ",";
}
}
int main() {
vector<int> v1 = { 1,2,3,4,5,6,7,8,9,10 };
vector<int> v2;
v2.resize(v1.size());
transform(v1.begin(), v1.end(), v2.begin(), NumberOperator());
printVector(v2); // 101,102,103,104,105,106,107,108,109,110,
return 0;
}将两个容器加工并拷贝到另一个容器
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class NumberOperator {
public:
int operator()(int num1,int num2) {
return num1+num2;
}
};
void printVector(vector<int>& v) {
for (int ele : v) {
cout << ele << ",";
}
}
int main() {
vector<int> v1 = { 1,2,3,4,5,6,7,8,9,10 };
vector<int> v2 = { 10,9,8,7,6,5,4,3,2,1 };
vector<int> v3;
v3.resize(v1.size());
transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), NumberOperator());
printVector(v3); // 11,11,11,11,11,11,11,11,11,11,
return 0;
}2.2 常用查找算法
2.2.1 find()
/*
在容器中查找元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 查找的元素
@return 返回查找元素的迭代器,找到则返回该元素的迭代器,否则返回end迭代器
*/
find(iterator beg, iterator end, value);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };
vector<int>::iterator it = find(v.begin(), v.end(),8);
if (it == v.end()) cout << "未找到";
else cout << *it; // 8
return 0;
}2.2.2 find_if()
条件查找
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param _callback 回调函数或者谓词(返回bool类型的函数对象)
@return 返回查找元素的迭代器,找到则返回该元素的迭代器,否则返回end迭代器
*/
find_if(iterator beg, iterator end, _ca11back);使用实例:回调函数作为条件
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool condition(int i) {
return i > 5;
}
int main() {
vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };
vector<int>::iterator it = find_if(v.begin(), v.end(), condition);
cout << *it; // 6
return 0;
}仿函数作为条件
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class Condition {
public:
bool operator()(int i) {
return i > 5;
}
};
int main() {
vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };
vector<int>::iterator it = find_if(v.begin(), v.end(), Condition());
cout << *it; // 6
return 0;
}2.2.3 adjacent_find()
查找重复元素,并且这些重复的元素是相邻的
/*
@param beg 容器开始选代器
@param end 容器结束选代器
@param _cal1back 回调函数或者谓词(返回bool类型的函数对象)
@return 返回相邻元素的第一个位置的迭代器
*/
adjacent_find(iterator beg,iterator end); // 范围内查找相邻重复元素
adjacent_find(iterator beg,iterator end,_callback); // 根据条件范围内查找相邻重复元素使用实例:两参数查找
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = { 1,2,3,4,5,6,6,7,8,9 };
vector<int>::iterator it = adjacent_find(v.begin(), v.end(), Condition());
cout << *it; // 6
return 0;
}2.2.4 binary_search()
二分查找法,注意:在无序序列中不可用
/*
@param beg 容器开始迭代器
@param end 容器结束选代器
@param value 查找的元素
@param _Pred 回调函数或者谓词
@return bool 查找返回true否则false
*/
bool binary_search(iterator beg, iterator end, value);
bool binary_search(iterator beg, iterator end, _Pred);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = { 1,2,3,4,5,6,6,7,8,9 };
bool res = binary_search(v.begin(), v.end(),5);
cout << res; // 1
return 0;
}2.2.5 count()
统计元素出现的次数
/*
@param beg 容器开始选代器
@param end 容器结束迭代器
@param value 回调函数或者谓词(返回boo1类型的函数对象)
@return int返回元素个数
*/
count(iterator beg,iterator end,value);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = { 1,1,2,2,2,3,3,3,4,5,5,6,6,6,6,6,7,7,8,8,9};
cout << count(v.begin(), v.end(), 1) << endl; // 2
cout << count(v.begin(), v.end(), 2) << endl; // 3
cout << count(v.begin(), v.end(), 3) << endl; // 3
cout << count(v.begin(), v.end(), 4) << endl; // 1
cout << count(v.begin(), v.end(), 5) << endl; // 5
cout << count(v.begin(), v.end(), 6) << endl; // 5
return 0;
}2.2.6 count_if()
根据条件统计元素出现的次数
/*
@param beg 容器开始迭代器
@param end 容器结束选代器
@param callback 回调函数或者谓词(返回bool类型的函数对象)
@return int 返回元素个数
*/
count_if(iterator beg,iterator end,_callback);使用实例,统计奇数的个数
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct con {
bool operator()(int i) {
return i % 2 != 0;
}
};
int main() {
vector<int> v = { 1,2,3,4,5,6,7,8,9 };
int res = count_if(v.begin(), v.end(), con());
cout << res << endl; // 5
return 0;
}2.3 常用排序算法
2.3.1 sort()
容器元素排序
/*
@param beg 开始迭代器
@param end 结束迭代器
@param _callback 回调函数或者谓词(返回boo1类型的函数对象)
*/
sort(iterator beg, iterator end);
sort(iterator beg, iterator end, _callback);使用实例:直接排序,默认升序排序
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = { 1,2,565,4,89,32,48,26,459,12 };
sort(v.begin(), v.end());
for (int ele : v) {
cout << ele << ","; // 1,2,4,12,26,32,48,89,459,565,
}
return 0;
}传入条件进行排序
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct con {
bool operator()(int a,int b) {
return b > a; // 升序排序
//return a > b; // 降序排序
}
};
int main() {
vector<int> v = { 1,2,565,4,89,32,48,26,459,12 };
sort(v.begin(), v.end(), con());
for (int ele : v) {
cout << ele << ","; // 1,2,4,12,26,32,48,89,459,565,
}
return 0;
}使用内置仿函数
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = { 1,2,565,4,89,32,48,26,459,12 };
sort(v.begin(), v.end(), greater<int>());
for (int ele : v) {
cout << ele << ","; // 565,459,89,48,32,26,12,4,2,1,
}
return 0;
}根据对象的属性排序
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Person {
int age;
Person() = default;
Person(int age) :age(age) {};
};
struct con {
bool operator()(Person& a, Person& b) {
return a.age > b.age;
}
};
int main() {
vector<Person> v = { Person(11),Person(13),Person(9) ,Person(10) ,Person(5) ,Person(20) };
sort(v.begin(), v.end(), con());
for (Person &ele : v) {
cout << ele.age << ",";
}
return 0;
}2.3.2 merage()
merge算法可以将容器元素合并,并存储到另一容器中,合并之后自动排序
注意:两个容器必须是有序的,并且新的容器需要自行开辟空间
/*
@param beg 1容器1开始迭代器
@param end1 容器1结束选代器
@param beg2 容器2开始迭代器
@param end2 容器2结束迭代器
@param dest 目标容器开始迭代器
*/
merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v1 = { 1,3,5,7,9 };
vector<int> v2 = { 0,2,4,6,8,10,12 };
vector<int> v3;
v3.resize(v1.size() + v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for (int ele : v3) {
cout << ele << ","; // 0,1,2,3,4,5,6,7,8,9,10,12,
}
return 0;
}2.3.4 random_shuffle()
对指定范围内的元素随机调整次序
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
*/
random_shuffle(iterator beg,iterator end)使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
srand(time(0));
vector<int> v = { 1,2,3,4,8,5,2,1,4,6,9,5,7,4 };
random_shuffle(v.begin(), v.end());
for (int ele : v) {
cout << ele << ","; // 瞎几把排
}
return 0;
}2.3.5 reverse()
反转指定范围的元素
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
*/
reverse(iterator beg,iterator end)使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
srand(time(0));
vector<int> v = {1,2,3,4,5};
reverse(v.begin(), v.end());
for (int ele : v) {
cout << ele << ","; // 5,4,3,2,1,
}
return 0;
}2.4 拷贝替换算法
2.4.1 copy()
copy算法将容器内指定范围的元素拷贝到另一容器中
注意目标容器需要自行开辟空间
/*
@param beg 容器开始选代器
@param end 容器结束迭代器
@param dest 目标起始选代器
*/
copy(iterator beg,iterator end,iterator dest);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = {1,2,3,4,5};
vector<int> v1;
v1.resize(v.size());
copy(v.begin(), v.end(), v1.begin());
for (int ele : v1) {
cout << ele << ","; // 1,2,3,4,5
}
return 0;
}2.4.2 replace()
replace算法将容器内指定范围的旧元素修改为新元素
/*
@param beg 容器开始选代器
@param end 容器结束选代器
@param o1dvalue 旧元素
@param oldvalue 新元素
*/
replace(iterator beg,iterator end,oldvalue,newvalue);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = {1,2,3,3,3,3,4,4,5,5};
replace(v.begin(),v.end(),4,400);
for (int ele : v) {
cout << ele << ","; // 1, 2, 3, 3, 3, 3, 400, 400, 5, 5,
}
return 0;
}2.4.3 replace_if()
replace_if算法将容器内指定范围满足条件的元素替换为新元素
/*
@param beg 容器开始选代器
@param end 容器结束选代器
@param _callback 函数回调或者谓词(返回Bool类型的函数对象)
@param newvalue 新元素
*/
replace_if(iterator beg,iterator end,_callback,newvalue);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct change {
bool operator()(int i) {
return i < 3;
}
};
int main() {
vector<int> v = {1,2,3,3,3,3,4,4,5,5};
replace_if(v.begin(),v.end(),change(),400);
for (int ele : v) {
cout << ele << ","; // 400,400,3,3,3,3,4,4,5,5,
}
return 0;
}2.4.4 swap()
/*
swap算法互换两个容器的元素
@param c1 容器1
@param c2 容器2
*/
swap(container cl,container c2);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v1 = {11,22,33};
vector<int> v2 = {44,55,66};
swap(v1, v2);
for (int ele : v1) {
cout << ele << ","; // 44,55,66,
}
for (int ele : v2) {
cout << ele << ","; // 11,22,33,
}
return 0;
}2.5 算数生成算法
使用以下算法需要引入#include <numeric>
2.5.1 accumulate()
ccumulate算法计算容器元素累计总和
使用需要引入
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 累加值
@return 返回累加后的值
*/
accumulate(iterator beg,iterator end,value)使用实例
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
using namespace std;
int main() {
vector<int> v1 = {1,2,3,4,5};
int res = accumulate(v1.begin(), v1.end(), 0);
cout << res << endl; // 15
int res1 = accumulate(v1.begin(), v1.end(),100);
cout << res1 << endl; // 115
return 0;
}2.5.2 fill()
fill()算法向容器中填充元素
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 填充元素
*/
fill(iterator beg,iterator end,value)使用实例
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
using namespace std;
int main() {
vector<int> v1(5,0);
fill(v1.begin(), v1.end(), 123);
for (int ele : v1) {
cout << ele << ","; // 123, 123, 123, 123, 123,
}
return 0;
}2.6 集合算法
2.6.1 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);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
using namespace std;
int main() {
vector<int> v1 = { 1,2,3,5,9,10 };
vector<int> v2 = { 1,3,5 };
vector<int> v3;
v3.resize(min(v1.size(),v2.size()));
set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for (int ele : v3) {
cout << ele << ","; // 1,3,5,
}
return 0;
}2.6.2 set_union()
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);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
using namespace std;
int main() {
vector<int> v1 = { 1,2,3,5,9,10 };
vector<int> v2 = { 2,5,8,30,50 };
vector<int> v3;
v3.resize(v1.size() + v2.size());
set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for (int ele : v3) {
cout << ele << ","; // 1,2,3,5,8,9,10,30,50,0,0,
}
return 0;
}2.6.3 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);使用实例
#include <iostream>
#include <algorithm>
#include <vector>
#include <numeric>
using namespace std;
int main() {
vector<int> v1 = { 1,2,3,5,9,10 };
vector<int> v2 = { 2,5,8,30,50 };
vector<int> v3;
v3.resize(max(v1.size() , v2.size()));
set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for (int ele : v3) {
cout << ele << ","; // 1,3,9,10,0,0,
}
return 0;
}