全排列(非递归和递归的方法)

推荐的良心博文http://www.cnblogs.com/chenyg32/p/3646074.html

例:求数组array[6]={1,2,3,4,5,6}的全排列,并在控制台中以从小到大的顺序输出。

非递归方法:

分析:我们需要理解如何通过上一个数求下一个数,这是我们循环的前提。例如这里有数字串364521,很显然它的下一个数字串应该是365124。这里我们给出算下一个数的过程:

编号012345
数字364521


1)对于数字串364521,我们从右向左找到第一组值使得array[i-1] < array[i],那么这里我们找到了array[2] < array[3](4 < 5),那么我们记下array[i-1]=array[2]=4这个数,令num=4;

2)从右往左(范围为[i,5])找到第一个大于num的数字,我们找到数字array[k]=array[3]=5,那么我们将该数字与num互换,然后我们得到数字串:

编号012345
数字365421


3)然后我们将数组array[k~5]的位置的数倒置一下,得到数字串:

编号012345
数字365124


这样我们就得到了结果。

算法思想重点指导:

我们发现下标从i到5的数字是降序排列,所以相对于他们这几个数来说已经没有下一个数字串了,即相对于他们自己来说他们是“最大”的,所以只好往高位换数字。剩下的很容易,大家自己思考一下就得出结果了。

#include <stdio.h>

#define N 6

void swap(int *a,int *b){//交换数组中的两个数
    int tmp;
    tmp=*a;
    *a=*b;
    *b=tmp;
}

int find(int *array,int num,int left){//从右向左找第一个大于num的数,返回该数的位置
    int i;
    for(i=N-1;i>=left;i--){
        if(array[i]>num)
            return i;
    }
    return -1;
}

void reverse(int * array,int start){//将数组从下标为start的地方开始到N-1的数字倒置
    int end=N-1,tmp;
    while(start<end){

        tmp=array[end];
        array[end]=array[start];
        array[start]=tmp;

        start++;
        end--;
    }
}

void Print(int * array){//输出数组array
    int i;
    for(i=0;i<N;i++)
        printf("%d ",array[i]);
    printf("\n");
}

int main(void){
    int array[N]={1,2,3,4,5,6};
    int i,num,k;
    Print(array);
    while(1){
        //第一个for循环用来找num
        for(i=N-1;i>0;i--){
            if(array[i-1]<array[i])
                break;
        }
        if(i==0)//如果发现现在数字串已经为最大的数(完全是从左到右的降序)那么break
            break;
        num=array[i-1];
        k=find(array,num,i);
        swap(&array[k],&array[i-1]);
        reverse(array,i);
        Print(array);
    }
    return 0;
}

递归方法

代码提示:我们这里用数组mark作为标记数组,result作为字符串的存储数组,x指的是result数组中还需要加几个数字便组成一个完整的字符串,例如result数组中已经为6543,那么还需要 加两个数字21或12即可组成654321或654312。

#include <stdio.h>
#include <memory.h>

#define N 10
#define n 4

int k;

void Print(int *result){
    int i;
    for(i=0;i<k;i++){
        printf("%d ",result[i]);
    }
    printf("\n");
}

void f(int *mark,int *result,int x){
    int i;
    if(x==1){
        for(i=1;i<=n;i++){
            if(mark[i]==0){
                result[k++]=i;
                Print(result);
                k--;
                return;
            }
        }
    }else{
        for(i=1;i<=n;i++){
            if(mark[i]==0){
                mark[i]=1;
                result[k++]=i;
                f(mark,result,x-1);
                k--;
                mark[i]=0;
            }
        }
    }
}

int main(void){
    int mark[N],result[N];
    k=0;
    memset(mark, 0, sizeof(mark));
    memset(result, 0, sizeof(result));
    f(mark,result,n);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值