使用遞歸函數生成排列(數據結構、算法與應用)


符號的定義:

  E={e1,e2,e3,······,en}表示n個元素的集合

  Ei為E移去第i個元素后剩余元素的集合

  perm(X)表示集合X中元素的排列方式

  ei.perm(X)表示perm(X)中每個排列方式的前面均加上ei以后得到的排列方式

基本思路:

  遞歸的基本部分:當n=1,即集合中只有一個元素時,只可能產生一種排列方式:perm(E)=(e)

  遞歸的遞歸部分:當n>1,perm(E) = e1.perm(E1)+e2.perm(E2)+e3.perm(E3)+······+en.perm(En)

分析過程

  首先定義一個數組

int E[4] = {0,1,2,3};

 

  則對這個數組中的元素進行排列的過程為:

  構造一個遞歸函數Perm(int list[],int begin,int end)

  其中第一個參數表示想要進行排列的數組,第二個參數表示進行排列數組中元素的起始編號,第三個參數則表示進行排列數組中元素的結束編號

  這個說起來有點繞口,舉個例子:

  如果對之前所定義的數組E中的所有元素進行全排列的話,那么這個函數應該寫作Perm(E,0,3),‘0’和‘3’分別代表數組的元素的起始編號和結束編號為e0,e3,也就是對E中的四個元素都進行全排列了

  可以很直觀的聯想到,當begin = end時,此時你想排列的只有一個元素,這就是遞歸的出口了

  那么在全排列的過程中,函數又該如何變化?

  一、當i = 0時,E0={e1,e2,e3}

  這個還好說,perm(E0)即為Perm(E,1,3),可以注意到上面的begin = 0,這里的begin = 1,比上面的多了1。

  二、當i = 1時,情況就有點難受了,此時E1 = {e0,e2,e3},0、2、3,從中間斷開了,這怎么搞?

  解決方法如下:

  我們可以將數組中元素e0和e1中的數據偷偷交換一下,用i = 0和情況來解決i = 1的情況,一開始e0 = 0,e1 = 1,交換以后就變成了e0 = 1,e1 = 0,此時E= {e1,e2,e3} = {0,2,3}

  當然每次交換后,還要再交換回來,因為在當i = 2時,e0和e2也是需要交換的,如果不交換回來的話,實際上執行的就是e1和e2的交換了,這里是一定要注意的。

  第三步和第四步,即當i = 2和i = 3的情況,省略

  綜上所述,我們的代碼為:

 1 #include<iostream>
 2 using namespace std;
 3 
 4 inline void Swap(int &a, int &b)
 5 {
 6     int temp = a;
 7     a = b;;
 8     b = temp;
 9 }
10 
11 void Perm(int list[], int begin, int end)
12 {
13     if (begin == end)
14     {
15         for (int i = 0; i <= end; i++)
16         {
17             cout << list[i];
18         }
19         cout << endl;
20     }
21     else
22     {
23         for (int i = begin; i <= end; i++)
24         {
25             Swap(list[begin], list[i]);
26             Perm(list, begin + 1, end);
27             Swap(list[begin], list[i]);
28         }
29     }
30 }
31 
32 int main()
33 {
34     int arr[3] = { 1, 2, 3 };
35     Perm(arr, 0, 2);
36     return 0;
37 }

  本文參考了:https://blog.csdn.net/xiazdong/article/details/7986015這篇博客以及《數據結構、算法與應用》

  表示感謝


免責聲明!

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



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