全排列

    列出一个数组的全排列,数组的size是n, 那么根据高中数学排列组合知识,它的全排列个数应该是 n!

    具体怎么求出来全排列,最容易想到的就是穷举法,列举出所有的可能。从递归的方式穷举,就很容易得出全排列的算法:

    假设数组(a,b,c,d)的全排列可以表示为{a,b,c,d},那么{a,b,c,d} = a{b,c,d} + b{a,c,d} + c{a,b,d}+ d{a,b,c}. 类似的,{a,b,c}又表示为a{b,c} + b{a,c} +c{a,b}.     数组只有一个元素的时候全排列就是他本身。那么全排列的递归实现:

void swap(int *x, int *y){
    int tmp = *x;
    *x = *y;
    *y = tmp;
}


void perm(int a[], int l, int r){
    assert(l<=r);
    if(l==r){ //出口,此时l~r区间表示的数组只有一个元素
        for(int i=0; i<=r; i++){
            cout<<a[i]<<" ";
        }
        cout<<endl;
    }else{
        for(int j=l; j<=r; j++){
            swap(&a[j], &a[l]);
            perm(a, l+1, r);   //注意下一级迭代在区间 l+1~m 之间进行,不是 j+1~m
            swap(&a[j], &a[l]);
        }
    }
}

     迭代中对称使用swap(&a[j], &a[l])是为了保证递归回溯回来之后,数组的元素顺序与初始顺序一致,比如[1,2,3,4]。这样在将下一个换到首地址的元素就一定是我们期望换的元素。    例如 [1,2,3,4]这个待全排列的数组,当 j=2时,全排列是 2{1,3,4},在执行perm(a,1,3)完之后,数组顺序一定是[2,1,3,4], 再执行swap(&a[j], &a[l]) 就是[1,2,3,4], a[3]当然也一定是3; j=3时我们如愿以偿将3换到首地址。 如果不成对使用,就无法保证每次还到首地址的是我们期望的元素。

       测试程序:

int main(){
    int n;
    cout<<"Input array size:";
    cin >>n;
    int array[] = (int *)malloc(sizeof(int)*n);
    cout<<"Input the array elements:"<<endl;
    for(int i=0; i<n; i++){
        cin >> *(array+i);
    }

    cout<<endl<<"Input array is:"<<endl;
    for(int i=0; i<n; i++){
        cout<<*(array+i)<<" ";
    }
    cout<<endl<<"Permutation:"<<endl;
    perm(array, 0, n-1);
    cout<<endl;
    free(array);
}
     测试结果:

Input array size:4
Input the array elements:
1 2 3 4

Input array is:
1 2 3 4
Permutation:
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 3 2
1 4 2 3
2 1 3 4
2 1 4 3
2 3 1 4
2 3 4 1
2 4 3 1
2 4 1 3
3 2 1 4
3 2 4 1
3 1 2 4
3 1 4 2
3 4 1 2
3 4 2 1
4 2 3 1
4 2 1 3
4 3 2 1
4 3 1 2
4 1 3 2
4 1 2 3





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值