【转】全排列算法非递归实现和递归实现
來源:http://blog.csdn.net/e3399/article/details/7543861
(一)遞歸的全排列算法
(A、B、C、D)的全排列為
1、A后面跟(B、C、D)的全排列
2、B后面跟(A、C、D)的全排列
3、C后面跟(A、B、D)的全排列
4、D后面跟(A、B、C)的全排列
而對1中的(B、C、D)照樣可以按照上面的形式進行分解。
1 /********************************************************************** 2 * Compiler: GCC 3 * Last Update: Mon 07 May 2012 07:08:58 PM CST 4 * File Name: 1.cpp 5 * Description: 利用stl中的next_permutation進行全排列 6 ************************************************************************/ 7 #include <iostream> 8 using namespace std; 9 10 template<typename T> 11 void permutation(T array[], int begin, int end) 12 { 13 int i; 14 15 if(begin == end){ 16 for(i = 0; i <= end; ++i){ 17 cout<<array[i]<<" "; 18 } 19 cout<<endl; 20 return; 21 } else { 22 //for循環遍歷該排列中第一個位置的所有可能情況 23 for(i = begin; i <= end; ++i) { 24 swap(array[i], array[begin]); 25 permutation(array, begin + 1, end); 26 swap(array[i], array[begin]); 27 } 28 } 29 } 30 31 int main(int argc, char **argv) 32 { 33 int a[4] = {1, 2, 3, 4}; 34 permutation(a, 0, sizeof(a) / sizeof(int) - 1); 35 36 return 0; 37 } View Code?
?
?
(二)非遞歸全排列算法,即按字典序排列算法。
基本思想是:
??? 1.對初始隊列進行排序,找到所有排列中最小的一個排列Pmin。
??? 2.找到剛剛好比Pmin大比其它都小的排列P(min+1)。
??? 3.循環執行第二步,直到找到一個最大的排列,算法結束。
如排列ABCDE,這是所有排列中最小的一個排列,剛好比ABCDE大的排列是:ABCED。
算法如下:
給定已知序列P =? A1A2A3.....An
對P按字典排序,得到P的一個最小排列Pmin = A1A2A3....An ,滿足Ai > A(i-1) (1 < i <= n)
從Pmin開始,找到剛好比Pmin大的一個排列P(min+1),再找到剛好比P(min+1)大的一個排列,如此重復。
1.從后向前(即從An->A1),找到第一對為升序的相鄰元素,即Ai < A(i+1)。
? 若找不到這樣的Ai,說明已經找到最后一個全排列,可以返回了。
2.從后向前,找到第一個比Ai大的數Aj,交換Ai和Aj。
3.將排列中A(i+1)A(i+2)....An這個序列的數逆序倒置,即An.....A(i+2)A(i+1)。因為由前面第1、2可以得知,A(i+1)>=A(i+2)>=.....>=An,這為一個升序序列,應將該序列逆序倒置,所得到的新排列才剛剛好比上個排列大。
4.重復步驟1-3,直到返回。
這個算法是C++ STL算法next_permutation的思想。
1 /********************************************************************** 2 * Compiler: GCC 3 * Last Update: Mon 07 May 2012 07:08:58 PM CST 4 * File Name: 1.cpp 5 * Description: 6 ************************************************************************/ 7 #include <iostream> 8 #include <cstring> 9 using namespace std; 10 11 //交換數組a中下標為i和j的兩個元素的值 12 void swap(int *a,int i,int j) 13 { 14 a[i]^=a[j]; 15 a[j]^=a[i]; 16 a[i]^=a[j]; 17 } 18 19 //將數組a中的下標i到下標j之間的所有元素逆序倒置 20 void reverse(int a[],int i,int j) 21 { 22 for(; i<j; ++i,--j) { 23 swap(a,i,j); 24 } 25 } 26 27 void print(int a[],int length) 28 { 29 for(int i=0; i<length; ++i) 30 cout<<a[i]<<" "; 31 cout<<endl; 32 } 33 34 //求取全排列,打印結果 35 void combination(int a[],int length) 36 { 37 if(length<2) return; 38 39 bool end=false; 40 while(true) { 41 print(a,length); 42 43 int i,j; 44 //找到不符合趨勢的元素的下標i 45 for(i=length-2; i>=0; --i) { 46 if(a[i]<a[i+1]) break; 47 else if(i==0) return; 48 } 49 50 for(j=length-1; j>i; --j) { 51 if(a[j]>a[i]) break; 52 } 53 54 swap(a,i,j); 55 reverse(a,i+1,length-1); 56 } 57 } 58 int main(int argc, char **argv) 59 { 60 int a[4] = {1, 2, 3, 4}; 61 combination(a, sizeof(a) / sizeof(int)); 62 63 return 0; 64 } View Code用STL實現:
?STL有一個函數next_permutation(),它的作用是如果對于一個序列,存在按照字典排序后這個排列的下一個排列,那么就返回true且產生這個排列,否則返回false。
1 /********************************************************************** 2 * Compiler: GCC 3 * Last Update: Mon 07 May 2012 07:08:58 PM CST 4 * File Name: 1.cpp 5 * Description: 利用stl中的next_permutation進行全排列 6 ************************************************************************/ 7 #include <iostream> 8 #include <algorithm> 9 using namespace std; 10 11 template <typename BidirectionalIterator> 12 void permutation(BidirectionalIterator array, int len) 13 { 14 sort(array, array + len); 15 do{ 16 for(int i = 0; i < len; ++i){ 17 cout<<array[i]<<" "; 18 } 19 cout<<endl; 20 }while(next_permutation(array, array + len)); 21 } 22 23 int main(int argc, char **argv) 24 { 25 int a[4] = {1, 2, 3, 4}; 26 permutation(a, sizeof(a) / sizeof(int)); 27 28 return 0; 29 } View Code文章參考來源:http://blog.csdn.net/hackbuteer1/article/details/6657435
http://plutoblog.iteye.com/blog/976216
http://blog.csdn.net/aipb2008/article/details/2227490
?
?
有一定約束條件的全排列
http://blog.csdn.net/hackbuteer1/article/details/6657435
???????? 對數1,2,3,4,5要實現全排序。要求4必須在3的左邊,其它的數位置隨意。?
????????????思路:首先使用上面的2種方法之一實現全排列,然后對全排列進行篩選,篩選出4在3左邊的排列。
?
1 #include "iostream" 2 #include "algorithm" 3 using namespace std; 4 5 void permutation(int* a,int length) 6 { 7 int i,flag; 8 sort(a,a+length); 9 do 10 { 11 for(i=0;i<length;i++) 12 { 13 if(a[i]==3) 14 flag=1; 15 else if(a[i]==4) //如果3在4的左邊,執行完代碼,flag就是2 16 flag=2; 17 } 18 if(flag==1) //如果4在3的左邊,執行完代碼,flag就是1 19 { 20 for(i=0;i<length;i++) 21 cout<<a[i]; 22 cout<<endl; 23 } 24 }while(next_permutation(a,a+length)); 25 26 } 27 int main(void) 28 { 29 int i,a[5]; 30 for(i=0;i<5;i++) 31 a[i]=i+1; 32 printf("%d以內所有4在3左邊的全排列結果為:\n",i); 33 permutation(a,5); 34 system("pause"); 35 return 0; 36 } View Code?
?
下面的分析來自C語言程序設計-顧志華:(page251)
對一組數窮盡所有排列,還有更好的方法。將一個排列看成一個長整數,則每個排列對應一個不同的長整數,所有可能的排列對應著一組有限的整數。將這組整數按從小到大的順序排成一個數列,從對應最小的整數開始,按數列的遞增順序順序逐一列舉每個排列對應的每一個整數,這能更有效地完成排列的窮舉。從一個排列找出對應數列的下一個排列可在當前排列的基礎上作部分調整來實現。倘若當前排列為1、2、4、8、7、6、5、3,并令其對應的長整數為12487653。要尋找比長整數12487653更大的排列,可從該排列的最后一個數字順序向前逐位考察,當發現排列中的某個數字比前一個數字大時,如本例中的8比它的前一個數字4大,這說明還有對應更大整數的排列。但為了順序從小到大列舉出所有的排列,不能立即調整的太大,如本例中將數字8與4交換得到的序列12847653就不是排列12487653的下一個序列。為得到排列12487653的下一個排列,應從已考察過的那部分數字中選出比數字4大,但又是它們中最小的那一個數字,比如數字5,該數字也是從后向前考察過程中第一個比4大的數字。5與4交換后,得到排列12587643,在前面數字1、2、5固定的情況下,還應選擇對應最小整數的那個序列。為此還需將后面那部分數字的排列順序顛倒,如將數字8、7、6、4、3的順序顛倒,得到排列1、2、5、3、4、6、7、8,這才是排列1、2、4、8、7、6、5、3的下一個排列。
轉載于:https://www.cnblogs.com/huashanqingzhu/p/3571089.html
總結
以上是生活随笔為你收集整理的【转】全排列算法非递归实现和递归实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP(一)
- 下一篇: 数学专业考研及读研目录[2014年11月