输出全排列
请编写程序输出前nnn个正整数的全排列(n<10n<10n<10),并通过9个测试用例(即nnn从1到9)观察nnn逐步增大时程序的运行时间。
输入格式:
输入给出正整数nnn(<10<10<10)。
输出格式:
输出1到nnn的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a1,a2,⋯,an{ a_1, a_2, \cdots, a_n }a1,a2,⋯,an排在序列b1,b2,⋯,bn{ b_1, b_2, \cdots, b_n }b1,b2,⋯,bn之前,如果存在kkk使得a1=b1,⋯,ak=bka_1=b_1, \cdots, a_k=b_ka1=b1,⋯,ak=bk 并且 ak+1<bk+1a_{k+1}<b_{k+1}ak+1<bk+1。
输入样例:
3
输出样例:
123
132
213
231
312
321
详细的过程已经写在注释里了,菜鸡第一次写博客,有什么不足还请大佬们指导
/*字典序全排列*/
#include<stdio.h>
#include<iostream>
using namespace std;
void pailie(int a[],int n);
main()
{
int n;
scanf("%d",&n);
int a[n],i;
for(i=1;i<=n;i++)//必须保证传入到函数中的一组数一定要已经是按从小到大排列好的,否则整
a[i-1]=i; //个算法就会崩溃
pailie(a,n);
return 0;
}
void pailie(int a[],int n)
{
int i;
int j, k;//这一套的基本思路就是在每一个从右向左数第一个比自己右边小的数字的右边的数每一
//次排列都是从一组升序的数一直拍到一组降序的数
while (1)
{
for(i=0;i<n;i++)
printf("%d",a[i]);//当第一次进入循环时,就会输出一次从开始就从小到大排好的数
printf("\n");
for (j = n - 2;a[j] > a[j + 1] && j >= 0 ; j--);
//这一步是从这一组数中右边(即从倒数第二个数判断,因为倒数第一个数右边没有数字)
//开始判断,找出第一个比自己右边数字小的数,下标存到j中
if (j < 0)
return; //当已经找不到还有比自己右边数字大的时候,就说明所有的全排列已经全部输
//出了(这就是上面那个j>=0判断条件的作用)。因为字典序全排列就是从一个最小的数,
//一直到最大的数1234----4321,当输到最大时,全排列就全部输出了
for (k = n - 1; k > j&&a[k] < a[j]; k--);
/*这一步是从这一组数中最右边开始判断的,在上一步找出j那个位置的数的右边的数字中,找出所有比j大的数中最小的数字,把他的下标存入k中,用来在下一步将j和k的值互换(右边的数从右至左是递增的,因此k是所有大于j的数字中序号最大者)*/
/*这里写的a[k]<a[j]就是从最右边找比a[j]大的数,只要是找到的第一个,就一定是比a[j]大的数中最小的那一个*/
swap(a[k], a[j]);
//这是将上面找到第一个比左边数字小的数字j和数字j右边比j大的数字中最小的数字k互换
//一下,这是为了把还没排在前面过的数字,排到前面去
for (int l = j + 1, r = n - 1; l < r; l++, r--)
swap(a[l], a[r]);
/*因为每一次一段数字排列完后,在j后面的数字最后都会是一个降序的数,j这个位置的数字后面的数是从大到小排序的,给对调一下就得出了下一次要输出的全排列*/
}
}