概述
算法主要由头文件<algorithm>、<numeric>、<functional>构成。
1、<algorithm>是所有STL头文件中最大的一个,范围涉及到遍历、排序、比较、查找、交换、复制、修改等等。
2、<numeric>体积很小,只包含几个序列上面进行简单数学运算的模板函数
3、<functional>定义了一些模板类,(eg:内建的函数对象模板)用以声明函数对象
常用的遍历算法
1、for_each//遍历容器
2、transform//搬运容器到另一个容器中
for_each
函数原型:
注:for_earch是STL中提供的遍历算法,用于遍历容器中的元素。beg为开始迭代器,end为结束迭代器,_func为函数或者函数对象(即仿函数),用于指定将遍历的元素进行何种操作。
eg:
#include <iostream>
using namespace std;
#include<functional>
#include<vector>
#include<algorithm>
//普通函数实现打印操作
void func(int val)//用于指定将元素进行何种操作
{cout << val << " ";
}
//用函数对象(仿函数)实现打印操作
class Func
{
public:void operator()(int val){cout << val << " ";}
};
int main()
{vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}for (vector<int>::iterator it = v.begin(); it != v.end(); it++)//用迭代器访问容器中的每个元素{cout << *it << " ";}cout << endl;for_each(v.begin(), v.end(), func);cout << endl;//换行for_each(v.begin(), v.end(), Func());//Func()为匿名的函数对象cout << endl;return 0;
}
transform
功能描述
将一个容器中的元素搬到另外一个容器中
注:1、beg1为原容器的开始迭代器,endl为原容器的结束迭代器,beg2为目标容器开始迭代器,
_func为函数或函数对象
2、若在搬运容器时,需要对容器内的容器进行一些运算,则可以使用函数或函数对象来实现
eg:
#include <iostream>
using namespace std;
#include<functional>
#include<vector>
#include<algorithm>
//用函数对象(仿函数)实现打印操作
class print
{
public:void operator()(int val){cout << val << " ";}
};
class Transform
{
public:int operator()(int val)//由于要返回值,因此返回类型为int{return val + 10;//作为transform的第四个参数,可以在搬运时对数进行相应的操作}
};
int main()
{vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}for_each(v.begin(), v.end(), print());//print()为匿名的函数对象cout << endl;vector<int>vTarget;vTarget.resize(v.size());//搬运目标函数时必须提前开辟足够的空间,否则无法正常搬运(即会报错)transform(v.begin(), v.end(), vTarget.begin(), Transform());//Transform()为匿名的函数对象for_each(vTarget.begin(), vTarget.end(), print());//打印容器vTarget中的元素cout << endl;return 0;
}
常用的查找算法
算法简介
find //查找元素
find_if //按条件查找元素
adjacent_find //查找相邻重复元素
binary_search //二分查找
count //统计元素个数
count_if //按条件统计元素个数
find
功能描述:
用于查找容器中的某个元素,若找到,则返回该元素的迭代器,找不到则返回结束迭代器
函数原型:
注:beg为起始迭代器,end为结束迭代器,value为要查找的元素
eg:
#include <iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string>
class person {
public:person(string name,int age){this->m_name = name;this->m_age = age;}bool operator==(const person &p)//相等则返回真,否则返回假{//由于person是自定义类型,因此编译器不知道怎么判断两个person类型的变量相等,因此需要在类中重载==if (this->m_name == p.m_name && this->m_age == p.m_age)return true;else return false;}string m_name;int m_age;
};
int main()
{//用find查找内置数据类型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;}//用find找自定义数据类型vector<person>vp;person p1("aaa",10);//实例化对象person p2("bbb", 20);person p3("ccc", 30);vp.push_back(p1);//将对象插入到动态数组中vp.push_back(p2);vp.push_back(p3);person fv("ccc",30);vector<person>::iterator pit=find(vp.begin(), vp.end(), fv);if (pit == vp.end()){cout << "未找到目标元素" << endl;}else{cout << "找到目标元素 姓名:" << pit->m_name << " 年龄: " << pit->m_age << endl;}return 0;
}
find_if
功能描述
按条件查找
函数原型
pred----即predicate表示谓词的意思。(即返回bool类型的仿函数)
eg:
#include <iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string>
class person {
public:person(string name,int age){this->m_name = name;this->m_age = age;}string m_name;int m_age;
};
class greater_five {
public:bool operator()(int val){return val > 5;//值大于5时返回真}
};
class greaterAge20
{
public:bool operator()(const person& p){return p.m_age > 20;//年龄大于20岁时返回真}
};
int main()
{//用find_if查找内置数据类型vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}vector<int>::iterator it = find_if(v.begin(), v.end(), greater_five());if ( it== v.end()){cout << "未找到" << endl;}else{cout << "找到元素为:" << *it << endl;}//用find_if找自定义数据类型vector<person>vp;person p1("aaa",10);//实例化对象person p2("bbb", 20);person p3("ccc", 30);vp.push_back(p1);vp.push_back(p2);vp.push_back(p3);vector<person>::iterator pit=find_if(vp.begin(), vp.end(), greaterAge20());if (pit == vp.end()){cout << "未找到年龄大于20岁的人" << endl;}else{cout << "找到了年龄大于20的人 姓名: " << pit->m_name << " 年龄: " << pit->m_age << endl;}return 0;
}
adjacent_find
功能描述:
查找相邻重复的元素(注意这里需要同时满足两个条件,即相邻和重复)
函数原型
此函数用于查找相邻重复元素,返回相邻元素的第一个位置的迭代器,未找到则返回v.end()
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
int main()
{vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}v.insert(v.begin(), 1);//1 0 1 2 3 4 5 6 7 8 9v.insert(find(v.begin(), v.end(), 7), 7);//在容器中查找元素为7的位置,并将7插入到该位置vector<int>::iterator it = adjacent_find(v.begin(), v.end());if (it == v.end()){cout << "未找到" << endl;}else{cout << "找到了重复相邻的元素为:" << *it << endl;//重复元素为7}return 0;
}
binary_search
功能描述:
用二分查找指定元素是否存在
函数原型:
查找指定元素,若查到,则返回true,否则返回false
注:二分查找必须要在有序的顺序表中才能使用(因为函数底层需要用到顺序表随机存取的特性,具体请看相应数据结构书籍)
二分查找相较于其他查找算法的优势在于时间复杂度低,只需logn的数量级
eg:
#include <iostream>
using namespace std;
#include<vector>
#include<algorithm>
int main()
{vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}v.insert(v.begin(), 1);//1 0 1 2 3 4 5 6 7 8 9v.insert(find(v.begin(), v.end(), 7), 7);//在容器中查找元素为7的位置,并将7插入到该位置bool ret=binary_search(v.begin(), v.end(), 9);if (ret)cout << "找到了" << endl;else cout << "未找到" << endl;return 0;
}
count
功能描述:
用于统计元素个数
函数原型:
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string>
class person {
public:person(string name,int age){this->m_name = name;this->m_age = age;}//由于count底层是通过判断两个值是否相等来统计元素个数的,而编译器并不知道怎么判断自定义数据类型是否相等,因此需重载==bool operator==(const person&p){if (this->m_age == p.m_age)return true;//底层是if判断,相等则返回true,count++else return false;}string m_name;int m_age;
};
int main()
{//count统计内置数据类型vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}v.insert(v.begin(), 5);int ret=count(v.begin(), v.end(), 5);//统计容器中5的个数cout << "容器中5的个数有:" << ret << "个" << endl;//count统计自定义数据类型vector<person>pv;person p1("张三", 18);//实例化对象person p2("李四", 20);person p3("王五", 18);pv.push_back(p1);pv.push_back(p2);pv.push_back(p3);person p("赵六", 18);ret=count(pv.begin(), pv.end(), p);//用于统计与赵六同岁的人有几个cout << "与赵六同岁的人有" << ret << "个" << endl;return 0;
}
count_if
功能描述:
按条件统计元素个数
函数原型:
pred称为谓词
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string>
class person {
public:person(string name,int age){this->m_name = name;this->m_age = age;}string m_name;int m_age;
};
class greaterFive
{
public:bool operator()(int val){return val > 5;//val大于5返回真,否则返回假}
};
class greater18
{
public:bool operator()(const person& p){return p.m_age > 18;}
};
int main()
{//count_if统计内置数据类型vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}v.insert(v.begin(), 5);int ret=count_if(v.begin(), v.end(), greaterFive());//统计容器中大于5的个数cout << "容器中大于5的个数有:" << ret << "个" << endl;//count统计自定义数据类型vector<person>pv;person p1("张三", 18);//实例化对象person p2("李四", 20);person p3("王五", 18);pv.push_back(p1);pv.push_back(p2);pv.push_back(p3);ret=count_if(pv.begin(), pv.end(), greater18());//用于容器中统计大于18岁的人数 greater18()为匿名对象cout << "容器中大于18岁的人有" << ret << "个" << endl;return 0;
}
常用的排序算法
算法简介
sort //对容器内的元素进行排序
random_shuffle //对元素进行洗牌,即将指定范围内的元素随机调整次序
merge //容器元素合并,并存取到另一容器中
reverse //反转指定范围的元素
注:调用时需包含头文件algorithm
sort
函数原型
注:若只指定待排序的区间(前两个参数),则sort会默认进行升序排序
若需要进行降序排列,则可自己写相应谓词,或通过调用STL中的greater来实现
random_shuffle
功能描述
将容器中的元素随机打乱。random_shuffle也称洗牌算法
函数原型
注:1、利用此算法来打乱容器中的元素只需要提供容器的起始和终止迭代器即可。
2、若需要让每次打乱的结果都不同,则需要提供随机数种子,即
srand((unsigned int)time(NULL));
merge
功能描述:
将两个容器中的元素合并在一起,并存储到另一个容器中
函数原型:
注:1、beg1为容器1的开始迭代器,end1为容器1的结束迭代器,beg2为容器2的开始迭代器,end2为容器2的结束迭代器。dest为目标容器的开始迭代器
2、容器1和容器2必须是有序的,且排列顺序必须一致,即都是升序或都是降序
3、必须先为目标容器创建足够的空间,否则会报错
4、合并后的元素仍然有序(具体实现原理可看归并排序相关内容)
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
class print {
public:void operator()(int val){cout << val << " ";}
};
void printFuc(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);}vector<int>vTarget;vTarget.resize(v1.size() + v2.size());//必须提前为目标容器创建足够的空间,否则会报错merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());//将v1和v2中的元素放到vTarget中for_each(vTarget.begin(), vTarget.end(), print());//print()为匿名函数对象cout << endl;for_each(vTarget.begin(), vTarget.end(), printFuc);//for_each中的第三个参数即可填函数名,也可以填函数对象cout << endl;return 0;
}
reverse
功能描述
将容器中的元素进行反转
函数原型:
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
class print {
public:void operator()(int val){cout << val << " ";}
};
int main()
{vector<int>v1;for (int i = 0; i < 10; i++){v1.push_back(i);}for_each(v1.begin(), v1.end(), print());cout << endl;//反转后cout << "--------反转后---------" << endl;reverse(v1.begin(), v1.end());for_each(v1.begin(), v1.end(), print());cout << endl;return 0;
}
常用的拷贝和替换算法
算法简介
copy //将容器内指定范围的元素拷贝到另一个容器中
replace //将容器内指定范围的旧元素修改为新元素
replace_if //将容器内指定范围内满足条件的元素替换为新元素
swap //互换两个容器的元素
copy
函数原型:
1、三个参数分别为:原容器的起始和终止迭代器,目标容器的起始迭代器
2、copy函数在实际开发中较少使用,可用‘=’平替
3、利用copy算法在拷贝时,目标容器需要提前开辟空间
replace
功能描述
将容器内指定范围的旧元素修改为新元素
函数原型
beg为起始迭代器,end为终止迭代器,oldvalue为旧元素,newvalue为新元素
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
class print {
public:void operator()(int val){cout << val << " ";}
};
int main()
{vector<int>v1;for (int i = 0; i < 10; i++){v1.push_back(i);}v1.insert(v1.begin(), 1);for_each(v1.begin(), v1.end(), print());cout << endl;replace(v1.begin(), v1.end(), 1, 2);//从容器起始位置遍历到终止位置,将元素1变成2for_each(v1.begin(), v1.end(), print());cout << endl;return 0;
}
replace_if
函数描述
将容器中满足条件的元素替换成新元素
函数原型
注:pred为谓词
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
class print {
public:void operator()(int val){cout << val << " ";}
};
class greater5
{
public:bool operator()(int val){return val > 5;}
};
int main()
{vector<int>v1;for (int i = 0; i < 10; i++){v1.push_back(i);}//替换前cout << "替换前" << endl;for_each(v1.begin(), v1.end(), print());cout << endl;replace_if(v1.begin(), v1.end(), greater5(), 1000);//从容器起始位置遍历到终止位置,将容器中大于5的元素全都替换成1000cout << "替换后" << endl;for_each(v1.begin(), v1.end(), print());cout << endl;return 0;
}
swap
函数描述
将两个相同类型容器中的元素互换
函数原型
注:1、c1为容器1,c2为容器2
2、swap交换元素时,注意交换的容器要同种类型
常用算术生成算法
注:算术生成算法属于小型算法,使用时应该包含头文件为#include<numeric>
算法简介
accumulate //计算容器元素累计总和
fill //向容器中添加元素
accumulate
算法描述:
计算容器元素累计总和
函数原型
注:value为起始值,即计算结果=起始值+容器元素累计总和
若只需计算容器元素累计总和,则起始值为0
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<numeric>int main()
{vector<int>v;for (int i = 0; i < 10; i++){v.push_back(i);}int total=accumulate(v.begin(), v.end(), 0);//计算容器元素总和,初始值为0int total1= accumulate(v.begin(), v.end(), 100);//初始值为100cout << "total=" << total << endl;cout << "total1=" << total1 << endl;return 0;
}
fill
功能描述
向容器中填充指定元素
函数原型
value为填充的值
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<numeric>
#include<algorithm>
void print(int val)
{printf("%d ", val);
}
int main()
{vector<int>v;v.resize(10);//创建10个空间,默认值为0for_each(v.begin(), v.end(), print);cout << endl;fill(v.begin(), v.end(), 10);//向容器v中填充10for_each(v.begin(), v.end(), print);cout << endl;return 0;
}
常用的集合算法
算法简介
set_intersection //求两个容器的交集
set_union //求两个容器的并集
set_difference //求两个容器的set
set_intersection
函数原型
四个参数分别为:容器1的起始和结束迭代器,容器2的起始和结束迭代器,目标容器的起始迭代器
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<numeric>
#include<algorithm>
void print(int val)
{printf("%d ", val);
}
int main()
{vector<int>v1;vector<int>v2;for (int i = 0; i < 10; i++){v1.push_back(i);//0-9v2.push_back(i + 5);//5-14}vector<int>target;target.resize(min(v1.size(), v2.size()));//比较v1和v2容器的大小,将较小的值作为目标容器开辟的预留空间//将v1和v2容器中的重复元素放到target容器中,并返回交集中最后一个元素的位置vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), target.begin());for_each(target.begin(), itEnd, print);//此处结束迭代器的位置应是itEnd,而不是target.end(),是因为交集元素的个数小于等于值最小的容器的大小//若选择target.end(),则有可能多打印几个0return 0;
}
注:求交集的两个集合必须是有序序列
set_union
算法描述
求两个集合的并集
函数原型
(与求交集类似)
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<numeric>
#include<algorithm>
void print(int val)
{printf("%d ", val);
}
int main()
{vector<int>v1;vector<int>v2;for (int i = 0; i < 10; i++){v1.push_back(i);//0-9v2.push_back(i + 5);//5-14}vector<int>target;target.resize(v1.size() + v2.size());//最特殊的情况为目标容器开辟空间需要两个容器相加//将v1和v2容器中的重复元素放到target容器中,并返回并集中最后一个元素的位置vector<int>::iterator itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), target.begin());for_each(target.begin(), itEnd, print);//此处结束迭代器的位置应是itEnd,而不是target.end(),是因为并集元素的个数小于等于两容器大小之和return 0;
}
注:两个集合必须是有序序列
set_difference
功能描述
求两个容器的差集
差集:具体来说,如果有两个集合A和B,那么A和B之间的差集是由所有属于A但不属于B的元素组成的集合
注:A和B之间的差集与B和A 之间的差集可能不同
函数原型
eg:
#include<iostream>
using namespace std;
#include<vector>
#include<numeric>
#include<algorithm>
void print(int val)
{printf("%d ", val);
}
int main()
{vector<int>v1;vector<int>v2;for (int i = 0; i < 10; i++){v1.push_back(i);//0-9v2.push_back(i + 5);//5-14}vector<int>target;target.resize(max(v1.size(), v2.size()));//最特殊的情况为两个容器没有交集,取两个容器中大的size作为目标容器开辟的空间大小//将v1和v2容器中的重复元素放到target容器中,并返回差集中最后一个元素的位置vector<int>::iterator itEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), target.begin());cout << "v1和v2的差集为:" << endl;for_each(target.begin(), itEnd, print);cout << endl;cout << "v2和v1的差集为:" << endl;itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), target.begin());for_each(target.begin(), itEnd, print);cout << endl;return 0;
}
注:求差集的集合必须是有序序列