生成排列的两种算法

本文介绍了如何生成1到n的全排列,通过两种不同的算法:一种基于回溯法,另一种则是将固定数字放在不同位置生成排列。这两种方法都用于解决排列问题,详细解释了算法思路并给出了AC代码。同时,文章提供了两种算法的输出结果,帮助读者理解其差异。
摘要由CSDN通过智能技术生成

生成排列就是研究数1,2,……,n生成所有的排列问题。下面根据一道例题来进行讲解说明这两种算法的思路和区别。


输出全排列(转自PTA)

请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。

输入格式:

输入给出正整数n(<10)。

输出格式:

输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a1​,a2​,⋯,an​排在序列b1​,b2​,⋯,bn​之前,如果存在k使得a1​=b1​,⋯,ak​=bk​ 并且 ak+1​<bk+1​。

输入样例:

3

输出样例:

123
132
213
231
312
321

题目思路清晰,就是直接输出生成的全排列,按字典序输出。


第一种算法

假定可以生成n-1个数的所有排列,那么就可以扩展方法来生成1,2,……,n这n个数的排列。举个例子:如果能生成数2,3,……,n的所有排列,并且在每个排列的前面加上数1,就可得出以1开头的排列数;接着,生成数1,3,……,n的所有排列,并且在每个排列的前面加上数2,就可得出以2开头的排列数……以此类推。重复这个过程直到最后生成1,2,……,n-1的所有排列,并且在每个排列的前面加上数n。

图解:

 假设我选择以1开头的排列,则第二个数就不能为1,只能是2,3;当第二个数选择2时,第三个数只能选3,走完一条路径即生成一个排列,最后输出;接着回退到上一步,第二个数选择3,则第三个数只能选择2,以此类推。类似于回溯法思想,走到路的尽头或者是中途走不下去了就回退到上一步。

AC代码

#include<iostream>
using namespace std;
int visited[10]={0};//0为没被访问,1为已使用 
int arr[10];//存储排列输出 
void func1(int step, int n)
{
	if(step==n+1)
	{
		for(int i=1;i<=n;i++)
		{
			printf("%d",arr[i]);
		}
		printf("\n");
	}
	else
	{
		for(int i=1;i<=n;i++)
		{
			if(visited[i]==0)
			{
				visited[i]=1;
				arr[step]=i;//当前步(当前位置)选择了i
				func1(step+1,n);
				visited[i]=0;
				//关键点,每次访问完都要置零,表示该数还没被使用过,
				//以便回溯到上一步的时候使用。
			}
		}
	}
}
int main()
{
	int n=0;
	scanf("%d",&n);
	func1(1,n);
	return 0;
}

输出结果:


第二种算法

方法如下:首先把1放到第一个位置,并且在[2, n]的位置生成2,3,……,n这n-1个数的全排列;接着,把1放到第二个位置,并且在第1和[3, n]的位置生成2,3,……,n这n-1个数的全排列……以此类推。直到最后把1放到第n个位置,并且在[1, n-1]的位置生成2,3,……,n这n-1个数的全排列。

实现代码(本题要求按字典序输出,该方法不符合题目要求)

#include<iostream>
using namespace std;
int arr[10];//存储排列输出 
void func2(int m, int n)
{
	if(m==n+1)
	{
		for(int i=1;i<=n;i++)
		{
			printf("%d",arr[i]);
		}
		printf("\n");
	}
	else
	{
		for(int i=1;i<=n;i++)
		{
			if(arr[i]==0)
			{
				arr[i]=m;//在第i个位置放置m(不用step,为了防止混淆),和算法1的主要区别
				func2(m+1,n);
				arr[i]=0;
			}
		}
	}
}
int main()
{
	int n=0;
	scanf("%d",&n);
	func2(1,n);
	return 0;
}

输出结果:

在最外层循环里,m=1,即第一次循环生成1在第一个位置的排列,第二次循环生成1在第二个位置的排列……以此类推,这就是第二种算法的主要思想。

总结

第一种算法是1,2,……,n这n个数依次放到第一个位置生成排列,第二种算法是把1(当然也可以是其它的数,例如n)依次放到第1,2,……,n这n个位置生成排列。还不是很理解的同学可以结合两种算法生成的输出结果对比看一下。希望能帮助到大家!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值