第 3 章 栈和队列 (算法 3.5,汉诺塔问题递归解法)

1. 背景说明

第 3 章 栈和队列 (算法 3.5,汉诺塔问题递归解法)_第1张图片

假设有 3 个分别命名为 X、Y 和 Z 的塔座,在塔座 X 上插有 n 个直径大小各不相同、依小到大编号为 1, 2,…,n 的圆盘。

现要求将 X 轴上的 n 个圆盘移至塔座 Z 上并仍按同样顺序叠排,圆盘移动时必须遵循下列规则:
(1) 每次只能移动一个圆盘;
(2) 圆盘可以插在 X、Y 和 Z 中的任一塔座上;
(3) 任何时刻都不能将一个较大的圆盘压在较小的圆盘之上。

2. 示例代码

1)hanoi.h

/* 汉诺塔定义头文件 */

#ifndef HANOI_H
#define HANOI_H

#define N 4				/* 初始汉诺塔层数 */
#define SIZE 3			/* 塔基个数 */

typedef struct {
	int** plates;
	int high[3];
} Tower;

void Init(int n, Tower* T);

void DestroyHanoi(Tower* T);

void PrintGraph(char t1, int n, char t2, Tower* T);

/* 算法 3.5, 将塔座 x 上按直径由小到大且自上而下编号为 1 至 n 的 n 个圆盘
   按规则搬到塔座 z 上。y 可用作辅助塔座 */
void Hanoi(int n, char x, char y, char z, Tower* T, int* step);

#endif // !HANOI_H

2) hanoi.c

/* 汉诺塔实现源文件 */

#include "hanoi.h"
#include 
#include 

void Init(int n, Tower* T)
{
	/* Apply for a memory to storage the pointer of int */
	T->plates = (int**)malloc(SIZE * sizeof(int*));
	/* Apply for a memory to storage the information of the blocks */
	for (int i = 0; i < SIZE; ++i) {
		T->plates[i] = (int*)malloc(n * sizeof(int));
	}
	
	/* Initial the plate information */
	T->high[0] = n;
	T->high[1] = 0;
	T->high[2] = 0;
	for (int i = 0; i < n; ++i) {
		T->plates[0][i] = n - i;
		T->plates[1][i] = 0;
		T->plates[2][i] = 0;
	}
}

void DestroyHanoi(Tower* T)
{
	for (int i = 0; i < SIZE; ++i) {
		free(T->plates[i]);
	}

	free(T->plates);
}

/* Show move n th block from plate t1 to plate t2 */
void PrintGraph(char t1, int n, char t2, Tower* T)
{
	/* Check the parameters */
	if ((t1 == t2) && (t1 != '\0')) {
		printf("Error: Can not move block for the same plate to the same plate.\n");
		return;
	}

	/* Move from */
	if (t1 == 'x') {
		T->plates[0][T->high[0] - 1] = 0;
		--T->high[0];
	}
	else if (t1 == 'y') {
		T->plates[1][T->high[1] - 1] = 0;
		--T->high[1];
	}
	else if (t1 == 'z') {
		T->plates[2][T->high[2] - 1] = 0;
		--T->high[2];
	}

	/* Move to */
	if (t2 == 'x') {
		T->plates[0][T->high[0]] = n;
		++T->high[0];
	}
	else if (t2 == 'y') {
		T->plates[1][T->high[1]] = n;
		++T->high[1];
	}
	else if (t2 == 'z') {
		T->plates[2][T->high[2]] = n;
		++T->high[2];
	}

	/* Initialize the block string graphic */
	char** s = (char**)malloc((N + 2) * sizeof(char*));
	for (int i = 0, j; i < N + 2; ++i) {
		s[i] = (char*)malloc((N + 1) * sizeof(char));
		for (j = 0; j < i; ++j) {
			if (i == N + 1) {
				s[i][j] = '-';
			}
			else {
				s[i][j] = '*';
			}
		}
		
		if (i == N + 1) {
			s[i][j - 1] = '\0';
		}
		else {
			s[i][j] = '\0';
		}
	}

	// Eg: N = 2
	// s[0][0] = '\0'
	// s[1][0] = '*', s[1][1] = '\0'
	// s[2][0] = '*', s[2][1] = '*', s[2][2] = '\0'
	// s[3][0] = '-', s[3][1] = '-', s[3][2] = '-', s[3][2] = '\0'
	for (int i = N - 1; i >= 0; --i) {
		printf("%-*s|%-*s|%-*s\n", N, s[T->plates[0][i]], N, s[T->plates[1][i]], N, s[T->plates[2][i]]);
	}

	printf("%-*s+%-*s+%-*s\n", N, s[N + 1], N, s[N + 1], N, s[N + 1]);
	printf("%-*s%-*s%-*s\n", N + 2, "x", N + 2, "y", N + 2, "z");   /* use "" not the '' */
	
	for (int i = 0; i < N + 2; ++i) {
		free(s[i]);
	}

	free(s);
}

static void Move(char x, int n, char z, Tower* T, int* step)
{
	/* If use (*step)++, do not forget add() cause the priority of the ++ is higher than *
	   You can also not add the() instead use ++*step, no problem but bad reading */
	++(*step);
	printf("The step %2d: Move %dth block from %c to %c\n\n", *step, n, x, z);
	PrintGraph(x, n, z, T);
	printf("\n");
}

/* 算法 3.5, 将塔座 x 上按直径由小到大且自上而下编号为 1 至 n 的 n 个圆盘
   按规则搬到塔座 z 上。y 可用作辅助塔座 */
void Hanoi(int n, char x, char y, char z, Tower* T, int* step)
{
	if (n == 1) {
		Move(x, 1, z, T, step);
	}
	else {
		Hanoi(n - 1, x, z, y, T, step);
		Move(x, n, z, T, step);
		Hanoi(n - 1, y, x, z, T, step);
	}
}

3) main.c

/* 汉诺塔主函数源文件 */
/* Note: Consider use stack to storage the information of the hanoi tower */

#include "hanoi.h"
#include 

int main(void)
{
	char x = 'x', y = 'y', z = 'z';
	printf("Initialize the %d layers hanoi tower:\n\n", N);
	Tower T = { 0 };
	Init(N, &T);
	PrintGraph('\0', 0, '\0', &T);
	printf("\n");
	int step = 0;
	Hanoi(N, x, y, z, &T, &step);
	DestroyHanoi(&T);

	return 0;
}

3. 输出示例

第 3 章 栈和队列 (算法 3.5,汉诺塔问题递归解法)_第2张图片

你可能感兴趣的:(#,数据结构(C语言版),算法,c语言,数据结构)