167 請程式設計實現全排列演算法
阿新 • • 發佈:2019-01-04
67、請程式設計實現全排列演算法。
全排列演算法有兩個比較常見的實現:遞迴排列和字典序排列。
/* 67、請程式設計實現全排列演算法。 全排列演算法有兩個比較常見的實現:遞迴排列和字典序排列。 (1)遞迴實現 從集合中依次選出每一個元素,作為排列的第一個元素,然後對剩餘的元素進行全排列, 如此遞迴處理,從而得到所有元素的全排列. (2)字典序排列 思想是讓排列成為可遞推的數列,也就是說從前一狀態的排列,可以推出一種新的狀態,直到最終狀態。 比如說,最初狀態是12345,最終狀態是54321。首先是12345,然後12354,然後12435,12453....逐漸地從後往前遞增。 演算法: 首先,將待排序列變成有序(升序)序列。然後,從後向前尋找,找到相鄰的兩個元素,Ti<Tj(j=i+1)。 如果沒有找到,則說明整個序列已經是降序排列了,也就是說到達最終狀態54321了。此時,全排列結束。 接著,如果沒有結束,從後向前找到第一個元素Tk,使得Tk>Ti(很多時候k=j),找到它,交換Ti跟Tk, 並且將Tj到Tn(Tn是最後一個元素)的子序列進行倒置操作。 輸出此序列。並回到第二步繼續尋找ij. 例如839647521是數字1~9的一個排列。從它生成下一個排列的步驟如下: 自右至左找出排列中第一個比右邊數字小的數字4 839647521 在該數字後的數字中找出比4大的數中最小的一個5 839647521 將5與4交換 839657421 將7421倒轉 839651247 所以839647521的下一個排列是839651247。 839651247的下一個排列是839651274。 遞迴實現版本在優化情況下要慢很多,主要原因可能在於太多的函式呼叫開銷, 但在不優化情況下執行比其它二個版本要快,原因可能在於程式結構更簡單,執行的語句較少。 比較而言,遞迴演算法結構簡單,適用於全部計算出所有的排列(因此排列規模不能太大,計算機資源會成為限制); 而字典序排列逐個產生、處理排列,能夠適用於大的排列空間,並且它產生的排列的規律性很強。 */ #include<iostream> #include<stdio.h> #include<algorithm> using namespace std; //template <typename T> int k,n=4; //遞迴 void rankRuc(char perm[],int n,int index) { if(index==n) { printf("%2d:",k++); for(int i=0;i<n;i++) printf("%c",perm[i]); printf("\n"); return ; } for (int i=index;i<n;++i) { swap(perm[i],perm[index]); rankRuc(perm,n,index+1); swap(perm[i], perm[index]); } } //字典序 void rankDic(char perm[],int num) { int i,k; if (num<1) return; while(true) { for (i=num-2;i>=0;--i) if (perm[i]<perm[i+1]) break; if (i<0) break; // 已經找到所有排列 for(k=num-1;k>i;--k) if(perm[k]>perm[i]) break; swap(perm[i],perm[k]); reverse(perm +i+1,perm+num); for(int i=0;i<n;i++) printf("%c",perm[i]); printf("\n"); } } int main() { char perm[]={"abcd"}; k=1; rankRuc(perm,4,0); //24個 printf("字典序排列:\n"); rankDic(perm,4); //24個 }