C++全排列

最近通过学习算法, 了解了全排列实现的几种方式,在此记录总结一下。

方式一:DFS深度优先搜索

该算法的实现可以当成模板来套用,当然本菜鸡习惯的写法不一定适合你,不过个人觉得还是比较好理解的,你可以多看看,总结总结,嘿嘿。

#include<iostream>
#include<stdio.h>
using namespace std;
const int eleNum = 5;
bool flag[eleNum] = {false};
int data[eleNum] = {0,1,2,3,4};
int count = 0;
void dfs(int depth, int path[])
{
	if(depth == eleNum)
	{
		for(int i = 0;i < eleNum;i++)
		{
			printf("%d ", path[i]);
		}
		printf("\n");
		count++;
		return;
	}
	for(int i = 0; i< eleNum;i++)
	{
		if(!flag[i])
		{
			path[depth] = data[i];
			flag[i] = true;
			dfs(depth+1,path);
			flag[i] = false;
		}
	}
} 
int main()
{
	int path[5];
	dfs(0, path); 
	printf("共计%d种排列方式",count);
	return 0;
}

方式二:next_permutation()

想看原文档的,请移步next_permutation
在这里只介绍两种常见的用法
注:next_permutation包含于头文件algorithm,用的时候别忘了。

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h> 
using namespace std;
int main()
{
	//用法1:对字符串全排列 
	string s = "01234";
	int count = 0;
	//int *data = new int[3]{0,1,2}; 
	do{
		cout << s << endl;
		count++;
	} while(next_permutation(s.begin(),s.end()));
	cout << "方式一共有" << count << "种情况" << endl;
	//用法2:对整形数组全排列 
	int data[5] = {0,1,2,3,4};
	count = 0;
	do{
		cout << data[0] << data[1] << data[2] << data[3] << data[4] << endl;
		count++;
	}while(next_permutation(data,data+5));
	cout << "方式二共有" << count << "种情况" << endl;
	return 0;
}

对于全排列中重复元素的处理

在待排列元素存在重复时,例如{0,0,0,0,0,1,1,1,1}在排列时,第一位和第二位元素交换位置之后,仍表示为一种情况,因此需要条件限制来给dfs减支,但待排列元素必须是有序的,否则就会有问题,问题在最后进行说明。
先看一下对于上面两种方式的重复处理

  • 对于dfs,去重方式为在for循环下做条件补充,在上面例子中做的补充应是if(i>0)&&data[i]!=data[i-1]&&!flag[i-1]) continue;,表示的含义为判断当前数是否与上一个元素重复,并且上一个元素还没被使用,此时跳过,不再递归。从而能达到减支的效果。
  • 对与全排列next_permutation()其本身就包含了重复元素的处理方式,很方便,其排列的顺序为序列的字典序的前后。

说明

  • 当待排列元素无序但不重复时
    dfs算法仍然有效,而next_permutation就会少很多次数,因为next_permutation总是从当前元素的字典序往下继续进行搜索,例如三个元素0,1,2
    初始为0,1,2时,有6种顺序,即012,021,102,120,201,210。这就意味着,如果从120开始的话,就只能获取到120及以后的情况,即只得到4种情况。
    因此在使用next_permutation时一定要小心,分清楚情况。
  • 当待排列元素无序且重复时
    此时,dfs和全排列函数得到的情况都会不正确,只有先排序才能进一步处理。

这间接说明,做全排列时,数组通常是自己构造的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值