分而治之思想:根据要求,大盘子不能压在小盘子上,所以必须把起始柱子上的n-1个盘子移到过渡柱子上,然后把最底下最大的那个盘子移到目标柱子上,再把过渡柱子上的n-1个盘子移到目标柱子上,任务完成。注意到从起始柱子上移动n-1个盘子到过渡柱子上,实质上与原来(从起始柱子移动n个盘子到目标柱子上)是同类型问题,但是规模减小了,可以一直得到n-2个盘子问题,n-3,n-4……,直到盘子数为1,直接移动即可。
复杂度分析:T(n) = 2T(n - 1) + o(1), 由大师定理,其复杂度为o(2^n)
递归实现:
void doing(int start, int end)
{
cout << start << "->" << end << endl;
}
void hanoi(int count, int start, int end, int temp)
{
if (count > 0)
{
hanoi(count - 1, start, temp, end);
doing(start, end);
hanoi(count - 1, temp, end, start);
}
}
#include<iostream>
usign namespace std;
int main()
{
hanoi(10, 1, 2, 3);
return 0;
}
尾部递归优化:注意到函数hanoi最后的执行语句是递归调用。函数调用时,主调函数的局部变量压入栈中,当被调函数返回时,恢复主调函数的局部变量。因为函数递归调用发生在主调函数的最后,所以当主函数恢复变量时,函数结束,又马上抛弃这些局部变量,所以可以省去最后这个递归调用。
概括原理:如果函数最后执行的语句是对函数自身的递归调用,则可以通过将调用参数赋给递归调用中指定的值并重复整个函数而消除此调用。
复杂度分析:画出递归树,其调用次数大概为未改进的四分之三,复杂度还是o(2^n),但是还是有改进。
实现:
void hanoi1(int count, int start, int end, int temp)
{
int swap;
while (count > 0)
{
hanoi1(count - 1, start, temp, end);
doing(start, end);
--count;
swap = start;
start = temp;
temp = swap;
}
}