问题:数字全排列,实现输入n位数,然后输出其所有的排列方式;
这道题是深入学习理解递归的典型题
递归思想:全排列可以理解为取出一个数,让剩下的数排列
剩下的数以此类推,直到最后一个数为止;
方法一:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#define max 100
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void sort(int a[],int n,int s,int r[],int m);
int main(int argc, char *argv[]) {
int n,m[max],i;
int r[max];
printf("请输入待排列数字的个数:");
scanf("%d",&n);
if(n>100){
printf("超出该程序排序的最大范围,输入错误;");
}else{
printf("请输入元素:");
for(i=0;i<n;i++){
scanf("%d",&m[i]);
}
sort(m,n,0,r,n);
}
return 0;
}
void sort(int a[],int n,int s,int r[],int m){ //其中m表示排列数字的个数,整个递归过程不发生改变;
//其实条件中的s是r数组的下标,r[s]存储递归每次取出的那个元素;
int i,j; //开始在该行定义了l=0;错误;导致下边的第一个for循环在第二次循环时还保留第一次了的值,必须每次保证清零;
int flag=0;
int b[max];
for(i=0;i<n;i++){ //该循环将数组中的第i个元素存入数组r中;
flag=1; //确定函数的范围是否到达该输出的时候;
r[s]=a[i];
int l=0;
for(j=0;j<n;j++){ //该循环的目的是将剩下的元素放入一个新数组中,方便下次递归运用;
if(i!=j){
b[l]=a[j];
l++;
}
}
sort(b,n-1,s+1,r,m);
}
if(flag==0){
int k;
printf("\n");
for(k=0;k<m;k++){
printf("%d ",r[k]);
}
printf("\n");
}
}
运行结果:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2csg3aq1UeRR1Ty0keYhnRzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcuIDN5EzN1IjM0EjMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
方法二:
代码如下:
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
void swap(int* a, int* b);
void perm(int str[], int m, int size);
int main(int argc, char *argv[]) {
int a[3] = {1,2,3};
perm(a,0,3);
return 0;
}
/* 交换两个数据 */
void swap(int* a, int* b)
{
int s = *a;
*a = *b;
*b = c;
}
/*递归思想:全排列可以理解为取出一个数,让剩下的数排列
剩下的数以此类推,直到最后一个数为止;
*/
void perm(int str[], int m, int size){
int i = 0,j = 0;
if(m == size){
for(i = 0; i < size; i++){
printf("%d ",str[i]);
}
printf("\n");
}
else{
for(j = m;j < size; j++){
swap(&str[j],&str[m]);
perm(str,m+1,size); //必须搞明白递归的栈机制原理!
swap(&str[j],&str[m]);
}
}
}
**前期在不运用递归的情况下思考出错的带代码如下**
//可能出发点有误,在代码的初期排列种类就不够!
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//数字全排列问题:就是将数字进行所有种类的组合,然后输出到屏幕上。组合不可以有重复的;例如123的六种组合方式;
/*思考:1,个人认为这是一个很有含量的题,入手点不知从何处下手;
2,感觉这类题目指针更容易解决;
3,其中指针指一指向数列的最后一位,指针二指向倒数第二位,指针二依次前移与指针一交换数据;数列遍历一次;
4,指针一前移一位,指针二同样指向指针一的前一位,然后再次像步骤3遍历.依次循环。
5,这样的思考有一个缺点就是可能存在相同的数据,这样交换完数据依然没变,相当于我们数学中不需要变换。因此在交换的过程中需要加入判断!
问题一:就是地址的数据交换完不回归原来的数据,所以必须有一步就是回归原来的数组;
问题二:这样交换位置后输出的全部仅仅是全排后的一部分,还有剩下一部分没有排列;
重新思考后:
依照刚才的方法:剩余的排序发现刚好是顺序排列前后递减后的顺序,比如:123,剩下的部分就是231,312;
*/
//void swap(int *,int *);
//int main(int argc, char *argv[]) {
// int a[MAX];
// int s[MAX]; //先定义一个较大的数组,这个数组用于存放输入的数列,也就规定了排序的数列的长度最大为100;
// int i,j,k,f,m,n;
// int *p,*q;
// printf("请输入需排序的数列的长度:");
// scanf("%d",&n);
// if(n>100){
// printf("该数列长度超出了该函数的功能范围;");
// }else{
//
// for(i=0;i<n;i++){ //输入数据,同时用另外一个变量存储数据;
// scanf("%d ",&a[i]);
// s[i]=a[i];
// }
// printf("\n");
//
// printf("输出全排后的数列:\n");
// for(f=0;f<n;f++){ //输出为排序的数列;
// printf("%d ",a[f]);
// }
// printf("\n");
//
// for(m=n-1;m>0;m--){ //实现了思考的第2步;
// p=&a[m];
// for(j=m-1;j>=0;j--){
// q=&a[j];
// swap(p,q); //实现了思考的第3步;
// for(k=0;k<n;k++){
// printf("%d ",a[k]);
// a[k]=s[k]; //数据回归原来的数组;
// }
// printf("\n");
// }
// }
///*现在需要实现“重新思考后”的问题 ;
// 感觉写一个方法对于解题更容易;
//*/
// int l,l_1,h;
// for(l=0;l<n;l++){
// h=a[n-1];
// a[l+1]=a[l];
// a[l+1]=s[l+1];
// }
// a[0]=a[n-1];
//
// for(l_1=0;l_1<n;l_1++){
// printf("%d ",a[l_1]);
// }
//
//
// }
// return 0;
//}
//
//void swap(int *a,int *b){ //数据交换函数;
// int m;
// m=*a;
// *a=*b;
// *b=m;
//}
运行结果: