如何用c++实现全排列功能(模拟next_permutation和prev_permutation)

前言

众所周知,c++中标准库已经包含了这两个排列的函数。
即,next_permutation()和prev_permutation()
但我觉得研究一下排列对算法来说绝对是有益无害,同时也能让我们在解题中更加顺手。
通晓原理才是永远的神~

PS::不过实际解题中,效率最关键,最好还是直接使用排序函数。

上一个排列prev_permutation()函数

要实现这个函数,我们得了解我们是如何判断上一个排列的。

举个例子,21045的上一个排列是20541.。

发现规律了嘛?当前的这个数5->4->0都是降序,而0->1突然变为升序。也就是说,从末尾开始降序(等于的情况也可),我们要一直找到一个升序点。

这个例子中,找到升序点,也就是1后,我们将0与1交换,然后对{1,4,5}进行从大到小的排序接在0的后面,就得到了原数的上一个排列。

接着我们可以快速的写出上排列的一个函数(假定以字符指针和长度作为函数参数):

void pre_permu(char *a,size_t n)
{
	int poi=-1;
	char ram;

	for (int i = n - 1; i > 0; i--)//找到不符合降序的位置
	{
		if (a[i] < a[i - 1])
		{
			poi = i;
			break;
		}
	}

	ram = a[poi - 1];//交换
	a[poi - 1] = a[poi];
	a[poi] = ram;
	
	sort(a + poi-1, a + n,greater<char>());//从大到小排序,greater是c++标准库的一个结构体,定义了比较原则
	if(poi==-1) cout<<"error"<<endl;
}

下一个排序next_permutation()函数

懂得了如何判断上一个排序,下一个函数自然也是手到擒来!

同样是先从末尾判断,不过这次是升序。

以12543为例,它的下一个排列是13245.

首先找到冲突点5->2,然后注意不能直接交换,与上一个函数不同的地方就在这里。

需要我们重新从末尾向冲突边界(此处为5)遍历,记录大于冲突值(此处为2)的最小值(也就是3),然后交换。

稍有不同,但是无伤大雅,下面是具体函数。

void next_permu(char *a,size_t n)
{
	int poi = -1,poi2=-1;
	int mi=1000,ram;

	for (int i = n - 1; i > 0; i--)//找冲突值
	{
		if (a[i] > a[i - 1])
		{
			poi = i;
			break;
		}
	}

	for (int i = n - 1; i > 0; i--)//找到大于冲突值的最小值
	{
		if (a[i]<mi && a[i] > a[poi - 1])
		{
			poi2 = i;
		}
	}

	if(poi==-1)cout << "error" << endl;

	ram = a[poi];
	a[poi] = a[poi2];
	a[poi2] = ram;

	sort(a + poi - 1, a + n);//默认为从小到大排序
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值