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

news2024/11/23 18:44:13

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 <stdlib.h>
#include <stdio.h>

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 <stdio.h>

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. 输出示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/964437.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试官问我MySQL和MariaDB的联系和区别,这我能不知道?

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

重装Windows10系统

以前清理电脑我一般是重置电脑的&#xff0c;但是重置电脑会清理C盘&#xff0c;新系统又遗留有以前的系统文件&#xff0c;导致后面配置环境遇到了棘手的问题&#xff0c;所以我打算重装系统。 第一次重装windows10系统&#xff0c;踩了很多坑&#xff0c;搞了两天才配回原来的…

Intel 80386运行模式

Intel 80386运行模式 一般CPU只有一种运行模式&#xff0c;能够支持多个程序在各自独立的内存空间中并发执行&#xff0c; 且有用户特权级和内核特权级的区分&#xff0c;让一般应用不能破坏操作系统内核和执行特权指令。 80386处理器有四种运行模式&#xff1a;实模式、保护模…

Day53|动态规划part14: 1143.最长公共子序列、1035. 不相交的线、53. 最大子序和

1143. 最长公共子序列 leetcode链接&#xff1a;力扣题目链接 视频链接&#xff1a;动态规划子序列问题经典题目 | LeetCode&#xff1a;1143.最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。 如果不存在 公共子序列 …

在工具提示中使用自绘修改字体

在上一篇文章中&#xff0c;我们学习了如何在应用程序中添加工具提示。在之前的例子代码中&#xff0c;我们通过简单地为创建的工具提示设置了目标字体&#xff0c;这种方法很简单&#xff0c;因为自始至终&#xff0c;我们都只创建了一个工具提示。 但是&#xff0c;如果在应…

【数据结构】2015统考真题 6

题目描述 【2015统考真题】求下面的带权图的最小&#xff08;代价&#xff09;生成树时&#xff0c;可能是Kruskal算法第2次选中但不是Prim算法&#xff08;从v4开始&#xff09;第2次选中的边是&#xff08;C&#xff09; A. (V1, V3) B. (V1, V4) C. (V2, V3) D. (V3, V4) …

亚马逊,eBay,速卖通买家账号是如何实现高权重,高存活率的

现在测评&#xff0c;补单机构越来越多&#xff0c;看似寻常的便捷渠道也潜藏着很大的风险&#xff0c;尤其是当大量机器代替人工、各种质量参差不齐的测评机构被曝光&#xff0c;跨境卖家“踩坑遇骗”的情况也就屡屡出现。很多卖家都选择自己注册买家账号&#xff0c;自己做测…

YOKOGAWA CP461-50处理器模块

数据处理能力&#xff1a; CP461-50 处理器模块具有强大的数据处理能力&#xff0c;用于执行各种控制和数据处理任务。 多通道支持&#xff1a; 该模块通常支持多通道输入和输出&#xff0c;允许与多个传感器和执行器进行通信。 通信接口&#xff1a; CP461-50 处理器模块通常…

一文了解气象站是什么,作用有哪些?

气象站被广泛应用于气象、农业、交通、能源、水利、环保等领域&#xff0c;是一种用于收集、分析和处理气象数据的设备&#xff0c;能够为人们提供及时、准确的气象数据和决策支持。 气象站一般由传感器、环境监控主机和监控平台组成。传感器能够测量各种气象要素&#xff0c;…

【leetcode 力扣刷题】数学题之数的开根号:二分查找

用二分查找牛顿迭代解决开根号 69. x的平方根367. 有效的完全平方数 69. x的平方根 题目链接&#xff1a;69. x的平方根 题目内容&#xff1a; 题意是要我们求一个数的算数平方根&#xff0c;但是不能使用内置函数&#xff0c;那么我们就暴力枚举。我们知道如果y>2的话&am…

2023-9-2 Kruskal算法求最小生成树

题目链接&#xff1a;Kruskal算法求最小生成树 #include <iostream> #include <algorithm>using namespace std;const int N 200010;// 与并查集中的p含义相同 int p[N];struct Edge {int a, b, w;bool operator< (const Edge & W)const{return w < W.w…

广场舞音乐制作软件,FL Studio怎么做广场舞音乐

广场舞一直以来都是许多人日常的消遣方式之一&#xff0c;富有节奏感的音乐能够让人沉浸其中&#xff0c;这也说明了音乐的重要性。那么如果我们想自己制作一个广场舞风格的音乐&#xff0c;需要具备哪些条件呢&#xff1f;今天我们就来说一说广场舞音乐制作软件&#xff0c;FL…

分页功能实现

大家好 , 我是苏麟 , 今天聊一聊分页功能 . Page分页构造器是mybatisplus包中的一个分页类 . Page分页 引入依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</ver…

指针结构体题

目录 初阶指针_指针的概念 1.使用指针打印数组内容 2.字符串逆序 3.整形数组和字符串数组 4.打印菱形 5.打印水仙花数 6.计算求和 结构体 7.喝汽水问题 8.程序死循环解释 9.选择题总结tips 今天是重点是指针&结构体题题目。&#x1f197;&#x1f197;&#x…

(超简单)将图片转换为ASCII字符图像

将一张图片转换为ASCII字符图像 原图&#xff1a; 效果图&#xff1a; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileWriter; import java.io.IOException;public class ImageToASCII {/*** 将图片转换为A…

dlopen “libnvcuvid.so“ failed!

在使用NVIDIA DALI库进行视频数据处理时&#xff0c;出现了以上打开libnvcuvid.so动态库错误的问题&#xff0c;如下图所示&#xff1a; libnvcuvid.so是使用CUDA进行硬编解码需要的一个库&#xff0c;使用NVIDIA DALI进行视频处理时会依赖它。 本人是在Docker容器中运行的程序…

Flink实时计算中台Kubernates功能改造点

背景 平台为数据开发人员提供基本的实时作业的管理功能,其中包括jar、sql等作业的在线开发;因此中台需要提供一个统一的SDK支持平台能够实现flink jar作业的发布;绝大多数情况下企业可能会考虑Flink On Yarn的这个发布模式,但是伴随云原生的呼声越来越大,一些企业不希望部…

肖sir__linux详解__002(系统命令)

linux系统命令 1、df 查看磁盘使用情况 &#xff08;1&#xff09;df 查看磁盘使用情况&#xff08;按kb单位显示&#xff09; &#xff08;2&#xff09;df -h 按单位显示磁盘使用情况 2、top 实时查看动态进程 &#xff08;1&#xff09;top 详解&#xff1a; 第一行&…

股票贷款行业,给你一个低成本有效的获客渠道

我们比市场上的同行公司具有更多的质量优势。我们的推广部门不断使用大数据引导和定位技术以及促销策略的迭代升级&#xff0c;具有足够强大的硬实力&#xff0c;可以引导客户提供更优质的投资者。为金融公司带来更好的资源。现在的股票加粉主要是&#xff1a;微信加粉/Q组/留电…

C语言:三子棋小游戏

简介&#xff1a; 目标很简单&#xff1a;实现一个 三子棋小游戏。三子棋大家都玩过&#xff0c;规则就不提及了。本博文中实现的三子棋在对局中&#xff0c;电脑落子是随机的&#xff0c;不具有智能性&#xff0c;玩家的落子位置使用键盘输入坐标。下面开始详细介绍如何实现一…