输入正数n,按字典序从小到大的顺序输出n个数的所有排列。两个序列的字典序大小关系等价于从头开始第一个不相同位置处的大小关系。
递归的边界应该很好理解吧,当集合s[]中没有一个元素的时候,按照上面的伪码,s[]中的元素只能向序列a[]中跑,s[]没了元素,那么序列a[]就是一个完整的序列了。那么,直接输出序列a[]即可。按照从小到大的顺序考虑s[]中的每个元素,每次递归的调用以a[]开始。
如果伪码了解了,那么就得用代码实现了。很容易想到序列a[]用数组保存集合s[]中跑过来得数字,而s[]呢?如果要完成老师布置的第一个题目,那么s[]中的元素根本不要保存,因为s[]中的元素往a[]中跑,那么,跑过来得数字就间接的保存在了序列a[]中,只要没在序列a[]中出现过的数字都可以备选。由于C/C++传递数组的时候传递的是数组的首地址,所以,还需要传一个到底填了多少个数,也就是到底填到数组的第几个位置来了,我们把这个参数取名为cur
生成1~n的排列
思路:
void print_permutation(序列A,集合S)
{
if ( S 为空 ) 输出序列 A;
else 按照从小到大的顺序依次考虑 S 的每个元素 v
{
print_permutation(在A的末尾添加v后得到的新序列,S-{v});
}
}
//思想:一个一个生成,每次生成时,看该元素在前面有没有存在过 //例如,生产第k个元素时,在1~n-1中找,前k-1个元素中没出现过的最小元素,给到a[k]。 #include <iostream> #include <cstdio> using namespace std; void print_permutation(int *A, int n, int cur)//每次处理A[]的一个元素(位子) { if(cur == n) { for(int i = 0; i < n; i++) printf("%d%c", A[i], (i == n - 1 ? ' ' : ' ')); return; } for(int i = 1; i <= n; i++)//尝试在a[cur]中填各种整数i { int ok = 1; for(int j = 0; j < cur; j++) if(A[j] == i) ok = 0; //A[0]~A[cur-1]中是否出现过i,则不能再选*/ if(ok) { A[cur] = i;//没有出现过则当前填进去i print_permutation(A, n, cur + 1); } } } int main() { int n; int *A; while(cin >> n) { A = new int[n]; print_permutation(A, n, 0); } return 0; }