全排列的递归和非递归解法

        输入n个整数,然后输出其全排列,如输入:3,输出:1 2 3   ,1 3 2 ,2 1 3 , 2 3 1 , 3 1 2 ,3 2 1.

递归解法:

思想:如2,3的全排列是以2开头的3的全排和以3开头2的全排,1,2,3的全排列是以1开头2 ,3的全排,以2开头1,3的全排和以3开头1,2的全排 。如此就可以用递归了。

#include<stdio.h>
#include<stdlib.h>
void print(int *a , int length)
{
int i;
    for(i = 0 ; i<length ; i++)
{
printf("%d " , a[i]);
}
printf("\n");
}
void swap(int *k , int *l)
{
int temp;
temp = *k;
*k = *l;
*l = temp;
}
void sort(int *a , int k , int length)
{
if(k>=length -1)
{
        print(a , length);
}
else
{
int i ;
for(i = k ; i < length ; i++)
{
swap(&a[k] , &a[i]);                //进入下一层前交换,求以a[i]开头的全排
sort(a , k+1 , length);             //递归进入下一层
swap(&a[k] , &a[i]);                //递归完后返回上一层时要恢复递归前的位置顺序
}
}
}
int main()
{
int n , i ;
scanf("%d" , &n);
int *a = (int*)malloc(sizeof(int)*n);
for(i = 0 ; i < n ; i++)
{
a[i] = i+1;
}
int length = n;
sort(a , 0 , length);
return 0;
}

个人认为一个可以用递归解决的问题一般主要考虑两点:从递归的第一层到第二层的过程和递归结束的过程。上面的问题还要考虑从递归的下一层返回到上一层前,需要恢复上一层的状态。

非递归解法:

思想:设数组长度为length,每次从右往左找到第一个下降的数(即a[i]>a[i-1]的a[i-1],令这个i-1等于k,记下k),再从右往左找到第一个大于a[k]的数记为a[m],交换a[k],a[m]的值,然后把下标为k+1到length-1的数值交换,即a[k+1]和a[length-1]交换,a[k+2]和a[length-2]交换,a[k+...]和a[length-...]交换.到最后一个排列是由大到小排列,如1,2,3的最后一个排列是3,2,1.找不到下降的数了,寻找过程终止。

#include<iostream>
using namespace std;
void print(int a[] , int g)
{
for(int i = 0 ; i<g ; i++)
            cout<<a[i]<<"  ";
cout<<endl;
}
void swap(int *a , int i , int j)
{
int temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
int main()
{
    int n , i;
cin>>n;
int *a = new int[n];
for(i = 0 ; i<n ; i++)
{
a[i] = i+1;
}
int k , g = n;
bool ok = true;
print(a , g);
while(ok)
{
int i;
     for(i=g-1; i>0; i--)
  if(a[i]>a[i-1])                                      
  {
  k = i-1;                            //寻找第一个下降的数
  for(int j=g-1; j>0; j--)       //交换
         if(a[j]>a[k])                 
  {
  swap(a,j,k);
  int n = g;
  while(k<n)
  {
  k++;
  n--;
  if(k<=n)  swap(a,k,n);
  }
  print(a , g);          交换后打印
 break;           
  }
  break;                        //重新从右往左找
}
  if(i==0) ok = false;          //i==0说明找不到下降的数了
}
return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值