使用递归函数生成排列(数据结构、算法与应用)

符号的定义:

  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这篇博客以及《数据结构、算法与应用》

  表示感谢

posted @ 2019-02-15 14:44  机智的小小帅  阅读(1780)  评论(0编辑  收藏  举报