1. 程式人生 > >演算法01:全排列遞迴演算法

演算法01:全排列遞迴演算法

全排列是指n個元素按一定順序的所有排列組合,如{1,2,3}三個元素的全排列為{1,2,3}、{1,3,2}、{2,1,3}、{2,3,1}、{3,1,2}、{3,2,1}共3!種。

常見排列的演算法一般有:

(1)遞迴法

(2)字典序法

(3)鄰位對換法

(4)遞增進位制數法

(5)遞減進位制數法

具體介紹:

(1)遞迴法

如求{1,2,3,4}的全排列

1.先考慮最後一個數{4}的全排列p(4)={{4}}一種;

2.{3,4}的全排列p(3,4)={{3,4},{4,3}}兩種;

3.{2,3,4}的全排列p(2,3,4)=2p(3,4)+3p(2,4)+4p(2,3),依此類推。

演算法思路:

1.首先定義一個數組和一個交換陣列元素的函式

int list[] = {1,2,3,4} , n = 4;

void swap(int *a, int *b)
{
     int temp;
    
     temp = *a;
     *a = *b;
     *b = temp;
}
2.遞迴函式的基本思想是:

(1)求1p(2,3,4),即以1開頭求出剩下的數{2,3,4}的全排列;

(2)為了求出2p(3,4)+3p(2,4)+4p(2,3),p(3,4)={{3,4},{4,3}},相當於把list陣列最後兩個元素交換,3p(2,4)又可以看成把3和2交換後求p(2,4),4p(2,3)是把4和3交換後求p(3,2);

(3)再求2p(1,3,4),相當於把2和1交換後求剩下數的全排列。

由此可得到遞迴函式,其中i為每次遞迴排列的第一個數的位置,k為要和第一個數交換的數的位置

void perm(int k)
{
     int i;
     
     if(k >= n){
        for(i = 0; i < n; i++)
            cout<<list[i];
            
        cout<<endl;
        total++;
     }else{
        for(i = k; i < n; i++){
            swap(&list[k], &list[i]); 
            
            perm(k+1);
            
            swap(&list[k], &list[i]); 
        }   
     }
}

完整演算法:
#include <cstdlib>
#include <iostream>

using namespace std;

int list[100], n,total;

void swap(int *a, int *b)
{
     int temp;
    
     temp = *a;
     *a = *b;
     *b = temp;
}

void perm(int k)
{
     int i;
     
     if(k >= n){
        for(i = 0; i < n; i++)
            cout<<list[i];
            
        cout<<endl;
        total++;
     }else{
        for(i = k; i < n; i++){
            swap(&list[k], &list[i]); 
            
            perm(k+1);
            
            swap(&list[k], &list[i]); 
        }   
     }
}

int main()
{   
    while(cin>>n){               
         for(int i = 0; i < n;)
             list[i] = ++i;
         total = 0;  
     
         perm(0);
         cout<<total<<endl;
    }
    
    system("PAUSE");
    return 0;
}