全排列问题
题目描述
按照字典序输出自然数 1 1 1 到 n n n 所有不重复的排列,即 n n n 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
输入格式
一个整数 n n n。
输出格式
由 1 ∼ n 1 \sim n 1∼n 组成的所有不重复的数字序列,每行一个序列。
每个数字保留 5 5 5 个场宽。
样例 #1
样例输入 #1
3
样例输出 #1
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
提示
1 ≤ n ≤ 9 1 \leq n \leq 9 1≤n≤9。
解法一:递归
code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int a[15]; //存放数据
bool vis[15]; //访问数组
int n;
int dfs(int cnt){ //num为排列的数
if(cnt==0){ //未排列的个数为0
int i;
for(i=n; i>=1; i--){ //输出 存放在数组中的n个数
printf("%5d", a[i]);
}
putchar('\n');
return 0;
}
int i;
for(i=1; i<=n; i++){ //每次选1-n中的一个数
if(vis[i]) continue; //这个数已经访问则寻找下一个未被访问的数
vis[i]=true;
a[cnt]=i; //将未被访问的数加入数组
dfs(cnt-1); //下一个数
vis[i]=false; //访问数组恢复
}
return 0;
}
int main(){
scanf("%d", &n);
int i;
for(i=1; i<=n; i++){
vis[i]=false;
}
dfs(n);
return 0;
}
解法二:编写next_permutation函数
函数的思路如下
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
从中选取第三个全排列
从最后一个数开始寻找第一个逆序的数 比如2 3 1
1 3 2 显然 2是第一个逆序的数 标记为start
2 3 1
start
找到刚好比start的数 也就是3 设置为temp 与他交换位置
3 2 1
start temp
最后将start后面的数进行倒置操作
得到
3 1 2
code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void reverse(int a[], int length, int index){
int i=index;
int j=length;
int temp;
while(i<=j){
temp=a[i];
a[i]=a[j];
a[j]=temp;
i++;
j--;
}
}
bool next_permutation(int a[], int length){
int i;
for(i=length; i>=1; i--){ //从最后一个数开始找到 第一个 不是升序的数
if(i-1 == 0) return false;
if(a[i]>a[i-1]) break;
}
int start=i-1; //记录上面找到的数:start
while(a[start]<a[i]){ //从start之后找到第一个刚好大于它的数
i++;
}
int temp=a[i-1]; //记录找到的数:temp 将它与之前找到的数:start 交换
a[i-1]=a[start];
a[start]=temp;
reverse(a, length, start+1); //将start后面的数倒置
return true;
}
int main(){
int n;
scanf("%d", &n);
int a[15]={0};
int i;
for(i=1; i<=n; i++){
a[i]=i;
}
do{
for(i=1; i<=n; i++){
printf("%5d", a[i]);
}
putchar('\n');
}
while(next_permutation(a, n));
return 0;
}