1 #include<iostream> 2 using namespace std; 3 template <typename T> 4 inline void swap(T* array, unsigned int i, unsigned int j) 5 { 6 T t = array[i]; 7 array[i] = array[j]; 8 array[j] = t; 9 } 10 11 /* 12 * 递归输出序列的全排列 13 */ 14 void FullArray(int* array, size_t array_size, unsigned int index = 0) 15 { 16 17 if (index >= array_size) 18 { 19 static int j = 1; 20 cout << "输出次数" << j++ <<": "; 21 for (unsigned int i = 0; i < array_size; ++i) 22 { 23 cout << array[i] << ' '; 24 } 25 cout << ' '; 26 27 } 28 29 for (unsigned int i = index; i < array_size; ++i) 30 { 31 swap(array, i, index); 32 cout << i << " :交换" << endl; 33 for (unsigned int i = 0; i < array_size; ++i) 34 { 35 cout << array[i] << ' '; 36 }cout << endl; 37 FullArray(array, array_size, index + 1); 38 swap(array, i, index); 39 cout << i << " :恢复" << endl; 40 for (unsigned int i = 0; i < array_size; ++i) 41 { 42 cout << array[i] << ' '; 43 }cout << endl; 44 } 45 } 46 void main() 47 { 48 int n; 49 cin >> n; 50 int *p = new int[n]; 51 for (int i = 0; i < n; i++) 52 p[i] = i; 53 FullArray(p, n); 54 delete[]p; 55
总之现在纸上规范化自己平时手动做全排的过程,我们会得到一个树形图。由n!我们可以得到这样一个结论:
如果从第一位开始从左到右进行选择的话,那么第一位有n种,第二位有n-1种……第n位有1种选择。
如果我们要设计递归,那就要给程序“分层次”
红圈圈出来的为第n次函数(第n-1次递归)的循环交换。
由于我们的程序没法向人一样把排列列出来,电脑每个内存只能存一个东西(别举共用体什么的反驳我///我只是在解释为啥函数要这么设计)
所以我们要一次生成一个排列。不能像上图那样把每一位的元素都先列好然后在组合起来(横着写),如果是这样内存开销是很大的。我们竖着写,写完一条链后从根节点再引出一条。
再看我们的函数生成全排的部分:
1 void FullArray(int* array, size_t array_size, unsigned int index = 0) 2 { 3 4 if (index >= array_size) 5 { 6 static int j = 1; 7 cout << "输出次数" << j++ <<": "; 8 for (unsigned int i = 0; i < array_size; ++i) 9 { 10 cout << array[i] << ' '; 11 } 12 cout << ' '; 13 14 } 15 16 for (unsigned int i = index; i < array_size; ++i) 17 { 18 swap(array, i, index); 19 FullArray(array, array_size, index + 1); 20 swap(array, i, index); 21 } 22 }
每次执行到循环语句都是:循环进行一次交换——》进入递归——》(递归中)循环进行一次交换——》下一次递归……直到最内层递归执行完毕后在从内到外执行排序回落(复位)语句。执行完毕后进行最外层第二次循环