全排列

全排列

全排列顾名思义,就是对一系列的单个字符进行排列,所有的排列结果就称为全排列,列如“1,2,3”,其全排列就有:“123”、“132”,“213“、”231“、312”,“321”,有6种,可以发现其全排列的个数就是n!
现在我们知道了什么是全排列,接着我们就要明白全排列的原理,因为全排列的个数是n!,它的个数恐怖式增长,我们不可能全部列出来,我们要培养计算机思维,这个问题如何用计算机解决,既然使用计算机,那我们就要考虑全排列的产生过程,即找规律
我们现在的全排列是按照字典序递增排列的,只有有一定的规则,我们才能方便找规律。
首先,举个例子1,2,3,4的全排列:1234,1243,1324,1342,·····4321
排列即交换某些字符的位置,那交换哪些字符能够保证使最后的排列保证递增排序呢,就像1234的下一个是1243,是3和4的位置进行交换,能不能是其他字符交换呢,那当然不能,因为1234的下一个1243就是字典序列最小的那一个,那下一个呢?1324,1后面的所有字符都发生了改变,1342,3后面的字符都发生了改变,那么,改变的位置k如何确定呢?
k之后的位置该如何改变呢?
我们上代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100], n;

int permutation()
{
	int flag = 0;//用来标记是否还有k,即是否是最后一个排列
	int k;
	for (int i = n - 2; i >= 0; i--)
	{
		if (a[i] < a[i + 1])//y用来找k的位置,从后往前找到一个可以交换的k的位置,小于就说明可以交换,有新的序列
		{
			flag = 1;
			k = i;
			break;
		}
	}
	if(flag == 0)
		return 0;
	for (int i = n - 1; i > k; i--)
	{
		if (a[i] > a[k])//找到了k的位置,那么该和哪一个位置的值交换呢,从后往前找到第一个比它大的值
		{
			swap(a[i], a[k]);
			break;
		}
	}
	sort(a + k + 1, a + n);//把k后面的值从小到大排序,为什么排序呢?
	//首先这样可以保证这种状态下字典序最小,还有为什么与k交换的是第一个比它大的值,为什么不是其他值,这个排序是非常重要的
	return 1;
}

int main()
{
	while (std::cin >> n)
	{
		int cnt = 1;
		for (int i = 0; i < n; i++)
		{
			std::cin >> a[i];
		}
		while (permutation())
		{
			cnt++;
			for (int i = 0; i < n; i++)
				std::cout << a[i] << " ";
			std::cout << std::endl;
		}
		std::cout << cnt <<std::endl;

	}
	return 0;
}

可能我的描述还是不能使你理解,那么希望你可以用1234来模拟一遍代码,来看一下执行过程,这个过程可以便于你的理解。
我们知道在C++里有很多封装好的库函数,没错,就是你想的那样,在C++有全排列的函数next_permutation(start,end),start是你要排列的首地址,end尾地址,作用就是求一个排列的下一个排列,可以遍历全排列。
这个函数需要头文件
#include
上代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100], n;

int main()
{
	while (std::cin >> n) {
		for (int i = 1; i <= n; i++)
			std::cin >> a[i];
		do {
			for (int i = 1; i <= n; i++)
				std::cout << a[i] << " ";
			std::cout << std::endl;
		}while(next_permutation(a+1, a +1+ n));
	}
	return 0;
}

不要感觉有了函数就感觉知道原理没什么用了,你只有知道原理,才能更好的使用,才能更灵活的使用。

外话:
递归实现全排列:

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[100], n;

void permutation()
{
	int flag = 0;
	int k;
	for (int i = n - 2; i >= 0; i--)
	{
		if (a[i] < a[i + 1]){
			flag = 1;
			k = i;
			break;
		}
	}
	if (flag == 0)
		return ;
	for (int i = n - 1; i > k; i--)
	{
		if (a[i] > a[k]){
			swap(a[i], a[k]);
			break;
		}
	}
	sort(a + k + 1, a + n);
	for (int i = 0; i < n; i++)
		std::cout << a[i] << " ";
	std::cout << std::endl;
	permutation();
	return ;
}

int main()
{
	while (std::cin >> n) {
		for (int i = 0; i <n; i++)
			std::cin >> a[i];
		permutation();
	}
}

其实递归实现我想了很久,但是还是没有想到怎么实现,那你可能会好奇上面的代码是什么鬼,你再看上面的代码和第一个代码就发现,递归循环调用同一个函数,我就偷了个懒,只是把while循环给换了种形式,希望有大佬可以帮助。

学习的时候看的大佬文章:大佬传送门

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值