使用递归函数生成排列(数据结构、算法与应用)
符号的定义:
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,此时E0 = {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这篇博客以及《数据结构、算法与应用》
表示感谢