汉诺塔非递归实现

发布时间 2023-04-08 00:11:53作者: XiaoXiaoMD

汉诺塔非递归实现

思路

使用栈结构模拟函数调用。

代码

#include <stdio.h>

// 栈帧结构体 
typedef struct {
	int pc, n;
	char from, via, to;
} Frame; 

// 全局变量(包括容量为 64 的栈和头指针) 
Frame stk[64], *top = stk - 1;
	
// 模拟函数调用,相当于将函数压入栈中
void call(int n, char from, char via, char to) {
	*(++top) = (Frame) { 0, n, from, via, to };
}

// 模拟函数执行完毕,相当于将函数从栈顶弹出 
void _return() {
	top--;
}

/**
	非递归汉诺塔算法 
	n: 汉诺塔层级
	from:初始柱子 
	via:途经柱子 
	to:目标柱子 
**/
void hanoi(int n, char from, char via, char to) {
	call(n, from, via, to);
	for (Frame *f; (f = top) >= stk; f->pc++) {
		/**
			我们知道想要完成汉诺塔移动操作,主要分为以下几个步骤(假设此处汉诺塔高度为 n) 
			1. 如果 n == 1 那么直接移动。 
			2. 如果 n != 1,就要先将 1 ~ (n - 1) 层的圆环从 A 柱移到 B 柱。 
			3. 再将第 n 层的圆环从 A 柱移到 C 柱。 
			4. 最后将  1 ~ (n - 1) 层的圆环从 B 柱移到 C 柱,堆叠上去。
			仔细观察 switch 就会发现它的分支操作恰好体现了上面的移动思路。 
		**/
		// switch 实现状态机功能 
		switch(f->pc) {
			case 0: 
			if (f->n == 1) {
				printf("%c -> %c\n", f->from, f->to);
				_return();
			}
				break;
			case 1: 
				call(f->n - 1, f->from, f->to, f->via);
				break;
			case 2: 
				call(1, f->from, f->via, f->to);
				break;
			case 3: 
				call(f->n - 1, f->via, f->from, f->to);
				break;
			default : _return();	
		}
	}
}

int main() {
	hanoi(3, 'A', 'B', 'C');
	return 0;
}

鸣谢

这里特别感谢 [蒋炎岩](Yanyan Jiang | Institute of Computer Software (nju.edu.cn)) 老师在操作系统课上展示的的汉诺塔非递归实现,B站 视频链接 在此。由于本人糟糕的 C 语言基础,对视频中涉及的 宏调用 不太理解,所以自己写了一个个函数来实现该功能。