(刘汝佳紫皮书)
生成1~n的排列。
对于一个长度为n数组长度的数组={0,1,2,3,..., n-1}。要想枚举它的所有的长度为n的全排列出来。
有两种选择:一个是直接枚举, 另外一个是使用递归来构造。
1.直接枚举
n 大的时候就要写 n-1个for循环
2.递归
递归函数: print_permutation(int n, int *A, int cur)
递归使用需要有判定界限,定义一个数组A,往A[]里面放我们需要排列的元素。 cur为当前要确定的元素位置。我们的判定界限则是: 当 n=cur 时 return 。
代码如下。
1 void print_permutation(int n, int* A, int cur) 2 { 3 if(n == cur)//排列到n个长度后输出 4 { 5 for(int i = 0; i < n; i++) 6 cout << A[i]; 7 cout << endl; 8 return; 9 } 10 else 11 { 12 for(int i = 0; i < n; i++) 13 { 14 int ok = 1; 15 for(int j = 0; j < cur; j++) 16 //判断i是不是已经使用过了 17 if(A[j] == i) 18 ok = 0; 19 if(ok) 20 { 21 A[cur] = i; 22 print_permutation(n, A, cur + 1); 23 } 24 } 25 } 26 }
生成可重集的排列
详细描述见刘汝佳紫皮书185页。
因为重集,所以只需要在上面代码上加重集元素出现次数的比较即可。
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 void printPermutation(int n, int* p, int cur, int* arr) //n是元素个数,p是初始元素集合,cur是当前位置,arr是目前已经排列的部分 6 { 7 int i, j; 8 if (cur == n) 9 { 10 for (i = 0; i < n; i++) 11 { 12 printf("%d ", arr[i]); 13 } 14 printf("\n"); 15 } 16 else 17 { 18 for (i = 0; i < n; i++) 19 { 20 if (i == 0 || p[i] != p[i-1]) //只需要检查第一个元素,以及与前一个元素不相同的元素即可,保证不重复 21 { 22 int c1 = 0, c2 = 0; 23 for (j = 0; j < cur; j++) //已经排列的元素中p[i]出现的次数 24 { 25 if (arr[j] == p[i]) 26 { 27 c1++; 28 } 29 } 30 for (j = 0; j < n; j++) //全部元素中p[i]出现的次数 31 { 32 if (p[i] == p[j]) 33 { 34 c2++; 35 } 36 } 37 if (c1 < c2) //保证不遗漏 38 { 39 arr[cur] = p[i]; 40 printPermutation(n, p, cur+1, arr); 41 } 42 } 43 } 44 } 45 } 46 47 int main() 48 { 49 int p[5] = {4, 1, 1, 4, 1}; 50 sort(p, p+5); //排序 51 int arr[5] = {0}; 52 printPermutation(5, p, 0, arr); 53 return 0; 54 }