借助堆栈以非递归(循环)的方式求解汉诺塔问题。
先把十分典型的递归版拿出来:
# include <iostream>
void Hanoi(char from, char to, char tmp, int n)
{
// from: 起始柱名 to:目标柱名 tmp:辅助柱名 n:个数
if (n == 0) return;
Hanoi(from, tmp, to, n - 1);
std::cout << from << " -> " << to << '\n';
Hanoi(tmp, to, from, n - 1);
}
int main(void)
{
Hanoi('A', 'C', 'B', 3);
return 0
}
模拟递归在运行当中在堆栈区层层叠加,就需要有一个栈,存放主调函数和被调函数的信息。信息,用结构体封装。
# include "Stack.h"
struct information {
char from;
char to;
char tmp;
int n;
};
void Hanoi(char from, char to, char tmp, int n)
{
Stack<information> s;
s.push(information{
from, to, tmp, n });
while (!s.empty())
{
information i = s.pop();
if (i.n-1 > 0) s.push(information{
i.from, i.tmp, i.tmp, i.n-1 });
std::cout << i.from << " -> " << i.to << '\n';
if (i.n - 1 > 0) s.push(information{
i.tmp, i.to, i.from, i.n-1 });
}
}
这样转化的意义在于节省空间。实际上,二者渐近意义上的空间复杂度是不变的,节省的那一部分来自于,递归每次要嵌套,在堆栈区调用一次递归就垒高一次信息,抵达最深时才会返回,所以空间复杂度的常数很大。而尾递归,每调用一个函数就执行完,消除掉当前函数在堆栈区占的位置。所以空间复杂度的常数会变小。