C++ STL标准库:算法algorithm


C++ STL标准库系列文章:

[STL] 1.简介
[STL] 2.序列容器 固定数组array(C++ 11)
[STL] 3.序列容器 动态数组vector
[STL] 4.序列容器 双端队列deque
[STL] 5.序列容器 双向链表list
[STL] 6.序列容器 单向链表forward_list(C++ 11)
[STL] 7.适配器简介
[STL] 8.容器适配器 栈stack
[STL] 9.容器适配器 队列queue
[STL] 10.容器适配器 优先队列priority_queue
[STL] 11.关联容器 集合set
[STL] 12.关联容器 映射map
[STL] 13.关联容器 多重集合multiset
[STL] 14.关联容器 多重映射multimap
[STL] 15.关联容器 无序集合unordered_set(C++ 11)
[STL] 16.关联容器 无序集合unordered_map(C++ 11)
[STL] 17.仿函数functor与函数对象
[STL] 18.预定义函数对象、仿函数适配器
[STL] 19.算法algorithm
[STL] 20.迭代器适配器
[STL] 21.空间配置器allocator

algorithm- C++ Reference (cplusplus.com)

1. 简介

STL的设计是将数据和算法独立开来,允许任何算法和任何容器交互。

算法对容器中数据进行操作。

容器用来存放数据。

迭代器则是算法与容器之间的桥梁。

分类:

  • 非修改序列算法

指不直接修改所操作的容器内容的算法。

  • 修改序列算法

指可以修改所操作的容器内容的算法。

  • 划分、排序、合并

包含对序列进行划分排序和合并的算法

  • 二分法查找算法

二分法查找

  • 堆算法

堆结构

  • 最大/最小值算法

求最大最小值

相关头文件:

  • #include <algorithm>

要使用STL中的算法函数必须包含头文件

  • #include <functional>

定义函数对象(function object)的类模板,算法、比较、逻辑操作

2. 非修改序列算法

算法名称功能
find根据值查找某元素
find_if查找某元素(当函数或仿函数的返回值为true)
find_first_of查找第二个区间中任何一个元素第一次出现的位置
for_each将每一个元素传到函数或仿函数中去
count返回某个元素出现的次数
count_if返回某个元素(当函数或仿函数的返回值为true)出现的次数
search查找一个序列出现的位置
search_n在范围中查找第一个连续n个元素都等价于给定值的子范围的位置

代码示例:

#include<iostream>

#include<vector>
#include<algorithm> //算法头文件

using namespace std;

bool   Is3(int x) //判断这个值是否为3
{
   return  x == 3;
}

struct  Is3_FO
{
   bool   operator()(int x) //判断这个值是否为3
   {
   	return  x == 3;
   }  
};

void  Print(int  x)
{
   cout << x << "	";//任意操作
}

int main()
{
   //数据都在容器中
   vector<int> v = {1,2,3,4,5};

   {	//查找 , 算法不能直接操作容器,它通过桥梁(容器迭代器来操作容器)
       //vector<int>::iterator  it=find< vector<int>::iterator, int>(v.begin(), v.end(), 3);
   	vector<int>::iterator  it = find(v.begin(), v.end(), 3);//类型自动推导
   	if (it != v.end()) //如果没有找到,返回end() 
   	{
   		cout << "找到了" << *it << endl;
   	}
   	else
   	{
   		cout << "没找到!" << endl;
   	}
   }

   {
   //与find类似,只不需要一元函数(或一元函数对象)对象返回为true时候就是找到了
   //find_if 会依次将 元素值放入  Is3中去检查,结果返回true时,认为找到了
   //vector<int>::iterator  it =find_if(v.begin(), v.end(), Is3);  //普通函数指针
    vector<int>::iterator  it = find_if(v.begin(), v.end(), Is3_FO() ); //函数对象
   if (it != v.end()) //如果没有找到,返回end() 
   {
   	cout << "找到了" << *it << endl;
   }
   else
   {
   	cout << "没找到!" << endl;
   }
   }

   {
   	//查找到  2,3中的任何一个值就认为查找到了
   	vector<int>  v2 = { 99,88}; //作为查找值
   	vector<int>::iterator  it =find_first_of(v.begin(), v.end(), v2.begin(), v2.end());
   	if (it != v.end()) //如果没有找到,返回end() 
   	{
   		cout << "找到了" << *it << endl;
   	}
   	else
   	{
   		cout << "没找到!" << endl;
   	}
   
   }

   {
   	//将每个元素依次作为参数传入到 一元函数Print中执行
   	for_each(v.begin(), v.end(), Print);//传入函数指针 
   	cout << endl;
   }

   {
   	vector<int>  v2 = { 1,2,2,2,2,3,4,5 };  
   	//统计一个元素出现的次数
   	cout << "2出现的次数" << count(v2.begin(), v2.end(), 2) << endl;;
   
   }
   
   {
   	vector<int>  v2 = { 1,2,2,2,2,3,4,5 };
   	//统计一个元素出现的次数
   	cout << "3出现的次数" << count_if(v2.begin(), v2.end(), Is3  ) << endl;;
   }

   {
   	//在容器序列中,查找一段子序列    12345,  比如 12 、234就是一个子序列
   	vector<int>  v2 = {  2,3,4 };
   	vector<int>::iterator  it=search(v.begin(), v.end(), v2.begin(), v2.end());
   	if (it != v.end()) //如果没有找到,返回end() 
   	{
   		cout << "找到了" << *it << endl;
   	}
   	else
   	{
   		cout << "没找到!" << endl;
   	}
   }

   {
   	vector<int>  v2 = { 1,2,3,4,4,4,5,6 };

   	//在v2中查找3个连续的元素4
   	vector<int>::iterator  it = search_n(v2.begin(), v2.end(), 3, 4);  
   	if (it != v2.end()) //如果没有找到,返回end() 
   	{
   		cout << "找到了" << *it << endl;
   	}
   	else
   	{
   		cout << "没找到!" << endl;
   	}
   }

   return 0;
}

3. 修改序列算法

算法名称功能
random_shuffle随机打乱指定范围中的元素的位置
replace将一个范围中值等价于给定值的元素赋值为新的值
replace_if与 replace类似(根据仿函数的比较规则)
replace_copy与 replace类似,同时拷贝到另外个容器
fill将一个范围的元素赋值为给定值
remove将一个范围中值等价于给定值的元素删除、并返回新结尾迭代器
reverse反转排序指定范围中的元素
unique删除指定范围中的所有连续重复元素,仅仅留下每组等值元素中的第一个元素。
transform对范围中的每个元素调用某函数,并将新值复制到另一个范围

代码示例:

#include<iostream>

#include<vector>
#include<algorithm> //算法头文件

using namespace std;

struct  Is3_FO
{
   bool   operator()(int x) //判断这个值是否为3
   {
   	return  x == 3;
   }
};

void  Print(int  x)
{
   cout << x << "	";//任意操作
}

int   Add2(int  x)
{
   return x + 2; //返回加2后的结果
}

int main()
{
   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,4,5 };

   	//随机打乱位置
   	random_shuffle(v.begin(), v.end());
   	//打印
   	for_each(v.begin(), v.end(), Print);
   	cout << endl; 
   }
   
   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,4,3,5 };

   	//替换v中所有元素为3的值替换为333
   	replace(v.begin(), v.end(),3,333);
   	//打印
   	for_each(v.begin(), v.end(), Print);
   	cout << endl;
   }

   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,4,3,5 };

   	//替换v中所有元素为Is3_FO()(x)返回true的值替换为333
   	replace_if(v.begin(), v.end(), Is3_FO(), 333);
   	//打印
   	for_each(v.begin(), v.end(), Print);
   	cout << endl;
   }

   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,4,3,5 };
   	vector<int> v2(6);

   	//与replace一样,但是不改变v的序列,只是将替换后的结果copy到 v2中
   	replace_copy(v.begin(), v.end(),v2.begin(), 3,  333);
   	//打印
   	for_each(v.begin(), v.end(), Print);
   	cout << endl;
   	//打印
   	for_each(v2.begin(), v2.end(), Print);
   	cout << endl;
   }

   {
   	vector<int>  v(5);
   	//将容器v中每个元素值填充为111
   	fill(v.begin(), v.end(), 111);
   	//打印
   	for_each(v.begin(), v.end(), Print);
   	cout << endl;
   
   }

   {
   	//数据都在容器中
   	vector<int> v = { 1,3,2,3,4,5 }; 
   	//删除所有的特定元素,但是不会改变容器的大小,只会将后面的元素往前移动,
   	//并返回删除后最后一个元素的结束位置
   	vector<int>::iterator  itNewEnd=remove(v.begin(), v.end(), 3); 

   	//打印
   	for_each(v.begin(), itNewEnd, Print);
   	cout << endl;   
   }

   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,4,5 };
   	 
   	//将v中的元素反序
   	 reverse(v.begin(), v.end());

   	//打印
   	for_each(v.begin(), v.end(), Print);
   	cout << endl;
   }

   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,3,3,4,5,3 };

   	//删除【连续相同元素】,只保留一个,但是不会改变容器的大小,只会将后面的元素往前移动,
   	//并返回删除后最后一个元素的结束位置,类似remove
   	vector<int>::iterator  itNewEnd =	unique(v.begin(), v.end());

   	//打印
   	for_each(v.begin(), itNewEnd, Print);
   	cout << endl;
   }

   {
   	vector<int > v = { 1,2,3,4,5 };
   	vector<int>  v2(5);

   	//把v中每个元素传入到 Add2中执行后拷贝到v2,有点类似于  for_each
   	transform(v.begin(), v.end(), v2.begin(), Add2);

   	//打印
       for_each(v.begin(), v.end(), Print);
   	cout << endl;

   	//打印
   	for_each(v2.begin(), v2.end(), Print);
   	cout << endl;
   }
    
   return 0;
}

4. 划分、排序算法

算法名称功能
partition对指定范围内元素重新排序,把传入仿函数结果为true的元素放在结果为 false的元素之前
stable_partition与 partition类似,但保留容器中元素的原相对顺序。
sort快速排序(根据仿函数的比较规则)
stable_sort与sort类似,但保留容器中相同元素的原相对顺序。
partial_sort只排序所有元素的部分,剩余元素的次序是未指定。比如一个赛跑成绩的集合,我们想知道前三名的成绩但并不关心其他名次的次序
nth_element使第n大元素处于第n位置,但不保证其他元素的顺序

代码示例:

#include<iostream>

#include<vector>
#include<algorithm> //算法头文件

using namespace std;

struct  Is2Or3
{
   bool   operator()(int x) //判断这个值是否为3
   {
   	return  x == 3 ||  x==2;
   }
};

bool   MyGreater(int a  ,  int b)  
{
   	return   a>b;
}

class  A
{
public:
   A(int _a, int _b) :a(_a), b(_b) {}
   int   a;
   int  b;
};

bool   MyGreaterA(A a, A b)
{
   return   a.a>b.a;
}

void  PrintA(A  a)
{
   cout << a.a<<"-"<<a.b << "	";//任意操作
}

void  Print(int  x)
{
   cout << x << "	";//任意操作
} 

int main()
{
   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,4,5 };

   	//分区域,  满足仿函数结果为true放到前面,为false的放到后面
   	vector<int>::iterator  itMid=partition(v.begin(), v.end(), Is2Or3());

   	//打印
   	for_each(v.begin(), itMid, Print);
   	cout << endl;

   	//打印
   	for_each(itMid, v.end(), Print);
   	cout << endl;
   }
    
   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,4,5 };

   	//分区域,  满足仿函数结果为true放到前面,为false的放到后面
   	//保留元素原有的先后顺序
   	vector<int>::iterator  itMid = stable_partition(v.begin(), v.end(), Is2Or3());

   	//打印
   	for_each(v.begin(), itMid, Print);
   	cout << endl;

   	//打印
   	for_each(itMid, v.end(), Print);
   	cout << endl;
   }

   {
   	//数据都在容器中
   	vector<int> v = { 1,2,3,4,5 };

   	//排序,默认升序
   	 //sort(v.begin(), v.end()  );
   	
   	 //降序
   	//sort(v.begin(), v.end(),greater<int>()); //使用STL预定义的函数对象
   	 sort(v.begin(), v.end(), MyGreater); //使用普通函数指针

   	//打印
   	for_each(v.begin(),   v.end(), Print);
   	cout << endl;
   }

   {
   	//数据都在容器中
   	vector<A> v = {A(1,111) ,A(3,330), A(4,444) , A(3,332) , A(2,222)  ,  A(3,331) };
   	 
   	//降序,保证相同元素值的原有顺序
   	stable_sort(v.begin(), v.end(), MyGreaterA); 

        //打印
   	for_each(v.begin(), v.end(), PrintA);
   	cout << endl;
   }

   {
   	//数据都在容器中
   	vector<int> v = {  99, 59, 60 ,23, 89,45,66  };

   	//想知道所有成绩最高的前三名,不关心后面的成绩顺序
   	partial_sort(v.begin(),  v.begin()+3,   v.end() ,greater<int>() );

   	//打印
   	for_each(v.begin(), v.end(), Print);
   	cout << endl;
   }

   { 
   	//数据都在容器中
   	vector<int> v = { 99, 59, 60 ,23, 89,45,66 };

   	//把第n大的元素排到第n个位置,不关心其它元素
   	 nth_element(v.begin(), v.begin() + 4, v.end());

   	//打印
   	for_each(v.begin(), v.end(), Print);
   	cout << endl;
   }

   return 0;
}

5. 堆算法

什么是堆?

堆(heap)是一棵完全二叉树(节点都优先集中在最左边),并满足仼意根节点大于(或小于)左右子节点,根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

若设二叉树的深度为k,除第 k 层外,其它各层 (1~k-1) 的结点数都达到最大个数,第k 层所有的结点都连续集中在最左边,这就是完全二叉树。

img

算法名称功能
make_heap用数组中元素构造出一个大根堆(默认)
push_heap入堆,将数组中最后一个元素放入堆中,使其依然是个堆
pop_heap出堆,将堆中的元素删除放到数组最后,排除最后一个,依然是堆
sort_heap将堆结构的元素按大小排序到数组,堆结构破坏

代码示例:

#include<iostream>

#include<vector>
#include<algorithm> //算法头文件

using namespace std;

void  Print(int x)
{
   cout << x << "  ";
}

int main()
{

   //提供一组凌乱的数据
   vector<int>  v = { 5,1,2,3,4 }; //很明显,它不是堆结构
 /*
                    5
   		1                2
      3       4 
 */

    //让数组中的元素组合成堆结构(默认大根堆)
    //每个根节点都大于  左右子节点 
   make_heap(v.begin(), v.end());  //5  4  2  3  1
   /* 
                  5
   		4             2
       3       1
   
   */
   //遍历
   for_each(v.begin(), v.end(), Print);
   cout << endl;

   //构造小根堆
   make_heap(v.begin(), v.end(),greater<int>());   //1  3  2  5  4
/*
              1
         3         2
    5       4 
*/
    //遍历
   for_each(v.begin(), v.end(), Print);
   cout << endl;

   cout << "--------------------------------------------" << endl;

   //放入一个元素到堆中,使其依然是一个堆,分两步
   //1.添加一个新元素到容器末尾 
   v.push_back(0);
   //2.调用push_heap让其依然是小根堆
   push_heap(v.begin(), v.end(),greater<int>()); //0  3  1  5  4  2
   /*
             0
      3              1
   5    4       2   
   */
   //遍历
   for_each(v.begin(), v.end(), Print);
   cout << endl;

   cout << "--------------------------------------------" << endl;

   //从堆中删除堆顶元素 ,使其依然是一个小根堆,分两步
  //1.调用pop_heap会将删除的堆顶元素移动到容器的尾部
   pop_heap(v.begin(), v.end(), greater<int>());    // 1  3  2  5  4    0(删除后移动到末尾的)
   //2.删除末尾元素,保证容器中正好是一个小根堆
   v.pop_back();
   for_each(v.begin(), v.end(), Print);  // 1  3  2  5  4  
   cout << endl;

   cout << "--------------------------------------------" << endl;
   //vecotr保存的小根堆,元素顺序并不是从大到小的
   //调用sort_heap之前必须保证是一个堆结构序列, 排序完之后,不再是堆了
   sort_heap(v.begin(), v.end() , greater<int>()); //将容器中元素排序
   for_each(v.begin(), v.end(), Print);  // 1 2 3 4 5  
   cout << endl;

   return 0;
}
OpenSAL1.1 包含了算法导论中所有数据结构和算法以及其他内容,本资源为该算法的静态链接 内容如下(*号表示1.1版本新增内容): 数据结构:一般堆、二项堆、斐波那契堆、红黑树、通用散列(采用全域散列和完全散列技术)、不相交集合、任意维数组、高维对称数组。 图论算法(兼容有向图,无向图):广度和深度优先遍历、确定图是否存在回路、拓扑排序、强连通分支、欧拉环(欧拉路径)、最小生成树(Kruskal、Prim)、单源最短路径(3种)、每对顶点间最短路径(2种)、最大流(2种)等等。 代数算法:霍纳法则计算多项式和、矩阵乘法(2种)、方阵的LUP分解、解线性方程组(2种)、矩阵求逆(2种)、求伪逆矩阵(2种)、解正态方程组(2种)、最小二乘估计(2种)、多元最小二乘估计*、快速傅里叶变换、快速傅里叶逆变换、多维快速傅里叶变换、多维快速傅里叶逆变换、快速向量求卷积(单变量多项式乘积)、快速张量求卷积(多变量多项式乘积)、多项式除法*、快速方幂和算法。 序列算法:最长公共子序列、KMP序列匹配*、键值分离排序。 数论算法:大数类(兼容浮点数、整数、与内置类型兼容运算)*、RSA加解密系统*、解同余方程*、孙子定理解同余方程组*、Miller_Rabin素数测试(产生大质数)*、随机数(实数、大数)*、欧几里得算法*。 计算几何算法:确定任意一对线段是否相交*、凸包*、最近点对*。 运筹学:线性规划(单纯形法)*、分配问题*、最优二度子图*、多01背包问题*
OpenSAL1.1 包含了算法导论中所有数据结构和算法以及其他内容,本资源为该算法的动态链接 内容如下(*号表示1.1版本新增内容): 数据结构:一般堆、二项堆、斐波那契堆、红黑树、通用散列(采用全域散列和完全散列技术)、不相交集合、任意维数组、高维对称数组。 图论算法(兼容有向图,无向图):广度和深度优先遍历、确定图是否存在回路、拓扑排序、强连通分支、欧拉环(欧拉路径)、最小生成树(Kruskal、Prim)、单源最短路径(3种)、每对顶点间最短路径(2种)、最大流(2种)等等。 代数算法:霍纳法则计算多项式和、矩阵乘法(2种)、方阵的LUP分解、解线性方程组(2种)、矩阵求逆(2种)、求伪逆矩阵(2种)、解正态方程组(2种)、最小二乘估计(2种)、多元最小二乘估计*、快速傅里叶变换、快速傅里叶逆变换、多维快速傅里叶变换、多维快速傅里叶逆变换、快速向量求卷积(单变量多项式乘积)、快速张量求卷积(多变量多项式乘积)、多项式除法*、快速方幂和算法。 序列算法:最长公共子序列、KMP序列匹配*、键值分离排序。 数论算法:大数类(兼容浮点数、整数、与内置类型兼容运算)*、RSA加解密系统*、解同余方程*、孙子定理解同余方程组*、Miller_Rabin素数测试(产生大质数)*、随机数(实数、大数)*、欧几里得算法*。 计算几何算法:确定任意一对线段是否相交*、凸包*、最近点对*。 运筹学:线性规划(单纯形法)*、分配问题*、最优二度子图*、多01背包问题*
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超级D洋葱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值