Intro:
- 绪论2:应用视角的操作系统。
- 目的:改写为非递归的汉诺塔,理解“状态机模型”。
一、递归版汉诺塔
课本上最基础的做法,递归是模拟某一步:把n-1
个盘子从from移到via,就能把剩下的一个盘子从from移到to,最后把n-1
个盘子从via移到to即可。
void hanoi_r(int n, char from, char to, char via) {
if (n == 1) {
printf("%c -> %c\n", from, to);
} else {
hanoi_r(n - 1, from, via, to);
hanoi_r(1, from, to, via);
hanoi_r(n - 1, via, to, from);
}
}
二、非递归版
非递归版的实现用了栈 Frame[64]
模拟整个调用过程。
typedef struct {
int pc, n; // 当前计数器、盘子数
char from, to, via;
} Frame;
// ...和__VA_ARGS__为可变参数列表,具体语法过程为:
// 1. {.pc ...} 代表 struct Frame 的初始化
// 2. 栈顶指针 top 下移,模拟把初始化好的 Frame 压入栈中
#define call(...) ({ *(++top) = (Frame) { .pc = 0, __VA_ARGS__ }; })
#define ret() ({ top--; }) // 出栈
#define goto(loc) ({ f->pc = (loc) - 1; }) // f->pc 代表了具体执行 swtich 中哪条指令
void hanoi_nr(int n, char from, char to, char via) {
Frame stk[64], *top = stk - 1;
call(n, from, to, via); // 初始化
for (Frame *f; (f = top) >= stk; f->pc++) {
n = f->n; from = f->from; to = f->to; via = f->via;
switch (f->pc) {
case 0: if (n == 1) { printf("%c -> %c\n", from, to); goto(4); } break;
case 1: call(n - 1, from, via, to); break;
case 2: call( 1, from, to, via); break;
case 3: call(n - 1, via, to, from); break;
case 4: ret(); break;
default: assert(0);
}
}
}
这段代码的执行过程需要多读两遍。
标签:via,递归,代码,hanoi,char,pc,汉诺塔,Frame From: https://www.cnblogs.com/7ytr5/p/18282287