算法學習(一) 全排列的幾種遞歸算法


      全排列是算法學習的一個初級問題,也是近幾年IT公司比較熱衷的問題。最近因為一個朋友的實際問題用到了類似全排列的算法,所以把相關的代碼總結一下。

一、問題描述

      全排列的問題非常簡單,比如給定三個數字1、2、3,請將三個數字的所有排列組合按大小順序給出。這樣我們期待的結果就是:123,132,213,231,312,321

二、第一種遞歸算法分析

      對於給定的n個數字,顯然有n!種排列方式。關鍵在於怎樣將所有的排列得到,一種顯然的方式是首先選出第一位上的數字,然后回溯選擇第二位上的數字,然后是第三位……只需要確保每一位上選擇的數字不重復就可以了。這種算法比較好理解,遞歸也比較好設計,先上代碼(c++):

 1 #include<iostream>
 2 #include<fstream>
 3 using namespace std;
 4 
 5 ifstream fin;
 6 ofstream fout;
 7 int flags[100];
 8 int numbers[100];
 9 int n;
10 
11 void search(int loc){
12     if(loc==n){
13         fout<<numbers[0]+1;
14         for(int i=1;i!=n;i++)
15             fout<<","<<numbers[i]+1;
16         fout<<endl;
17     }else{
18         for(int i=0;i!=n;i++)
19             if(flags[i]){
20                 flags[i]=0;
21                 numbers[loc]=i;
22                 search(loc+1);
23                 flags[i]=1;
24             }
25     }
26 }
27 
28 int main(){
29     
30     //fin.open("input.txt",ios::in);
31     fout.open("QPL.txt",ios::out);
32     
33     cin>>n;
34     for(int i=0;i!=n;i++)
35         flags[i]=1;
36     search(0);
37 }

      算法的關鍵就是search函數的實現。首先是退出條件的確定,search函數從左到右每個坑里填一個數字,當loc==n的時候填完所有的坑,這樣一個排列便完成了。然后是往每個坑里填數字的過程,就是那個for循環,對於每個坑數字從0到n填,同時判定沒有重復使用。

      這種實現的好處是比較直觀,可拓展性比較強。大家可以試一下修改邊界條件的判定標准會有什么效果。

三、第二種遞歸算法分析

      網上還有這樣一種看似簡潔的遞歸算法。算法通過觀察全排列的產生方式,以123為例,他的全排列為123,132,213,231,312,321.通過觀察可以發現,123的全排列就是1+(23的全排列)加上2+(13的全排列)加上3+(12的全排列)這里的遞歸的設計就是1+perm(23)然后交換1和2再執行2+perm(13)然后交換2和3執行3+perm(23)。

      代碼設計如下:

 1 #include <iostream>
 2 #include <fstream>
 3 #include <stdlib.h>
 4 
 5 using namespace std;
 6 
 7 void swap(char *a,char *b)
 8 {
 9     char temp;
10     temp=*a;
11     *a=*b;
12     *b=temp;
13 }
14 
15 void Perm(char *pszStr, int k, int m)
16 {
17     if (k == m)
18     {
19         static int s_i = 1;
20         cout<<"the "<<s_i ++<<" line"<<pszStr<<endl;
21     }
22     else
23     {
24         for (int i = k; i <= m; i++) //第i個數分別與它后面的數字交換就能得到新的排列
25         {
26             swap(pszStr + k, pszStr + i);
27             Perm(pszStr, k + 1, m);
28             swap(pszStr + k, pszStr + i);//恢復現場
29         }
30     }
31 }
32 
33 int main(int argc, const char * argv[])
34 {
35     char str[]="1234";
36     Perm(str,0, 3);
37     return 0;
38 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM