通过swap方式生成的全排列并不是字典顺序的:
#include<cstdio> #include<cstring> #include<iostream> #include<string> #include<algorithm> using namespace std; int A[20]; int cnt; int recur; void perm(int cur, int n, int *A) { recur++; if(cur==n)//empty { cnt++; for(int i=0;i<n;i++) printf("%d ", A[i]); printf(" "); } else { for(int i=cur;i<n;i++) { swap(A[i], A[cur]); perm(cur+1, n, A); swap(A[i], A[cur]); } } } int main() { int n; cin>>n; for(int i=0;i<n;i++) A[i]=i+1; perm(0, n, A); cout<<cnt<<endl; cout<<recur<<endl; return 0; }
上面代码n=3时,输出如下:
1 2 3
1 3 2
2 1 3
2 3 1
3 2 1
3 1 2
6
16
可以看出叶子节点数目为6,需要递归16次(即所有的节点数目)
第一层cur 0
第二层cur 1
第n+1层cur n 都是叶节点。
但是要注意,3开头的就不是字典顺序了。
按顺序填充遍历方式能保证字典顺序;
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n, A[50], isp[50], vis[50]; int cnt; int recur; void dfs(int cur) { recur++; if(cur == n ) { cnt++; for(int i = 0; i < n; i++) printf("%d ", A[i]); printf(" "); } else for(int i = 1; i <= n; i++) if(!vis[i]) { A[cur] = i; vis[i] = 1; dfs(cur+1); vis[i] = 0; } } int main() { scanf("%d", &n); memset(vis, 0, sizeof(vis)); dfs(0); printf("%d ", cnt); printf("%d ", recur); return 0; }
输出结果:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
6
16
可以看出树的节点数和上面的算法是一样的,所以效率是差不多的。但是这个算法却可以保证字典顺序生成排列。