return F(n - 1) * n
这个递归式,其中边界是if(n == 0) return 1;
const int maxn = 11; //P为当前排列,hashTable记录整数x是否已经在P中 int n, P[maxn], hashTable[maxn] = {false}; //当前处理排列的第 index 号位 void generateP(int index){ if (index == n + 1){ //递归边界,已经处理完排列的1~n位 for (int i = 0; i <= n; ++i) { cout << P[i] << " "; //输出当前排列 } cout << endl; return; } for (int x = 1; x <= n; ++x) { //枚举1~n,试图将x插入P[index] if (hashTable[x] == false){//如果x不在P[0]~P[index-1]中 P[index] = x; //令P的第index位为x,即把x加入当前排列 hashTable[x] = true; //记录x已在P中 generateP(index + 1);//处理排列的第index+1号位 hashTable[x] =false; //已处理完P[index]为x的子问题,还原状态 } } }
体会一下哈希表的使用和递归的感觉。首先hashTable大小是11,即最多存储11个bool值,而n是控制全排序位数大小的变量。整段代码前半主要时候控制递归边界用的。可以如此理解:刚开始hashTable的值全部是false,因为P没有存入任何元素。若现在开始存入第一位为1,我们就会发现从第二位开始就有奇怪的事情发生了,由于第一位1的存入,hashTable[1]的值就是true了,因此在递归到下一个generateP的函数时1就无法被调用,轮到2了,一直这样1、2、3、4、5。这就是我们编程之后第一行是12345的原因了。之后的肯定就是先使hashTable[5]=false
回到上一次让hashTable[4]=false
那里,继续递归进行循环。
递归的艺术就是可能意识不到这种倒推的感觉,他自己就动起来了。在一次次的递归过程中,先解决最后一个问题,再从最后一个问题向前回溯,找到第n-1个问题,这个逻辑过程让人着迷。也正是这种非正常的逻辑过程让一些复杂的问题变得简单,递归加上hash就能将本需要重复计算的结点跳过,减少运行时间和内存调用。
其实