汉诺塔的非递归算法

news2024/12/23 12:48:16

对于汉诺塔问题,我们都普遍认为这个是一个典型的递归问题,然而递归需要使用到系统对应的栈,开销比较大,因此我在想使用非递归算法来解决它,然而网上绝大部分的教程都是自己模拟了一个栈,因此我在考虑写一篇blog记录一下。

问题描述

将一个柱子中的所有圆盘移动到另一个柱子,移动过程需遵守以下规则:每次只能移动一个圆盘,而且只能移动某个柱子上最顶部的圆盘;移动过程中,必须保证每个柱子上的大圆盘都位于小圆盘的下面。
在这里插入图片描述

递归算法

这个算法还算比较好理解,我们计A,B,C盘,那么假设我们要把n圆盘,从A移到C,可以拆分为小问题,我们把上面n-1个的圆盘看成整体,让它先到B,那么最下面的一个移动到C,再把n-1个从B移动到C。
这样就把复杂问题,拆分成更简单的问题,那么退出条件就是只剩下一个圆盘,即为,A->C

#include<iostream>
using namespace std;
//算法设计实验1,汉诺塔问题
//采用递归方法解决
//n个棋盘  A B C为基座   最终达成目标A全部移到C
//性能 T(n)=2T(n-1)+1  1忽略 那么时间复杂度为O(2^n),相当的大,因此对于n较大的时候,运行时间较长
void Hanoi1(int n,char A,char B,char C)
{
	if (n == 1)
	{
		cout  << A << " -> "<< C << endl;
		return;
	}
	Hanoi1(n - 1, A, C, B);//相当于先把上面n-1盘子,移到中间
	cout<< A << " -> " << C << endl;
	Hanoi1(n - 1, B, A, C);//相当于先把上面n-1盘子,移到中间
}
int main()
{
	int n;
	cout << "请选择汉诺塔层数:";
	cin >> n;
	//递归算法
	Hanoi1(n, 'A', 'B', 'C');
	return 0;
}

非递归运行结果

非递归算法

当然我参考的时候发现,很多人模拟了栈作为非递归算法,这种当然可以,但是其核心思想还是用栈的方法,实现递归,本质上和系统的栈思想一致。因此我在考虑用真正非递归的思想来解决这个问题。
由于问题较为复杂,因此咱们先举出比较简单的例子。
假设只有2个盘子
在这里插入图片描述

步骤1234567
移动的盘子0102010
步骤0->20->12->10->21->01->20->2

我们可以发现其中是有规律的:

  1. 如果把三个柱子围成一个环,盘子总数为N,
  2. 如果N为偶数:奇数号盘每次2步;偶数号盘每次1步;
  3. 如果N为奇数:奇数号盘每次1步;偶数号盘每次2步;
  4. 当三个柱子都不为空则优先移动最小的盘子。
#define N 150
#define X dish[i].dnum
#define Y dish[i].lnum
#define SP dish[i].peg
//向右走一步
struct dish
{
	int dnum;	//自身编号
	int lnum;	//下面的盘子
	int peg;	//所在的柱子
}dish[N];
//初始化每个柱的状态为空
int s[3] = {};
//向右走一步
int mov1(int sp, int x)
{
	if (s[(sp + 1) % 3] > x)//要移动的目标是可以承载当前盘子的
	{
		//printf("\nmove1\n");
		printf("%d %d --> %d\n", x, sp, (sp + 1) % 3);
		s[dish[x].peg] = dish[x].lnum; //x盘所在柱子减去当前盘,顶盘变为x盘的下一个
		dish[x].lnum = s[(dish[x].peg + 1) % 3]; //x盘的落点即x转移后的下面的盘
		s[(dish[x].peg + 1) % 3] = dish[x].dnum; //x盘转移到的柱子顶盘值变为x盘值
		dish[x].peg = (dish[x].peg + 1) % 3; //x盘所在柱子变为落点柱子
		return 1; //转移成功
	}
	else return 0; //转移失败
}
//向右走两步
int mov2(int sp, int x)
{
	if (s[(sp + 2) % 3] > x)//要移动的目标是可以承载当前盘子的
	{
		//printf("\nmove2\n");
		printf("%d %d --> %d\n", x, sp, (sp + 2) % 3);
		s[dish[x].peg] = dish[x].lnum; //x盘所在柱子减去当前盘,顶盘变为x盘的下一个
		dish[x].lnum = s[(dish[x].peg + 2) % 3]; //x盘的落点即x转移后的下面的盘
		s[(dish[x].peg + 2) % 3] = dish[x].dnum; //x盘转移到的柱子顶盘值变为x盘值
		dish[x].peg = (dish[x].peg + 2) % 3; //x盘所在柱子变为落点柱子
		return 1; //转移成功
	}
	else return 0; //转移失败
}
int main()
{
	int n;
	cout << "请选择汉诺塔层数:";
	cin >> n;
	int i, change = 1, j;
	for (i = 0; i < n; i++)
	{
		dish[i].dnum = i; //作为盘子的唯一标识,顶层为0,最高级的最大盘子为N-1
		dish[i].lnum = i + 1; //底层盘子的下一层为N,即空柱
		dish[i].peg = 0; //初始化,所有盘子都在A柱	
	}
	s[0] = 0; //当前0柱上最顶端的盘子值
	s[1] = n;
	s[2] = n;//空柱,屏蔽大于n的盘子
	while (s[0] < n || s[1] < n)
	{
		j = 0;
		for (i = 0; s[j] <= n && i < n; i++) //不为空柱则向下找盘子
		{
			if (s[0] >= n && s[1] >= n)
				return;
			if (s[dish[i].peg] != dish[i].dnum) //当上面有盘子时不能移动
				continue;
			if ((n % 2 == 0 && X % 2 == 0) || (n % 2 == 1 && X % 2 == 1))
				change = mov1(SP, X);
			else change = mov2(SP, X);
			if (!change)
			{
				if (s[0] < n && s[1] < n && s[2] < n)
				{
					for (int k = 0; s[k] != 0; k++)
						j = k;
				}
				else j = (j + 1) % 3; //该柱上没有盘子可以移动则更换柱子
			}
		}
	}
	return 0;
}

因此可以得到非递归版本的,汉诺塔答案!

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

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

相关文章

【C++初阶】:内联函数

内联函数 一.宏函数二.内联函数三,是否成为内联函数四.内联函数的跨文件使用 一.宏函数 在c语言中&#xff0c;如果一个函数较短并且会被重复使用&#xff0c;那么我们就可以把该函数换成一个宏函数。 贴个小知识&#xff0c;宏函数有许多的坑也是面试官喜欢考的点&#xff0c;…

如何使用美颜SDK制作美妆相机?美颜SDK代码分析

随着时代的发展&#xff0c;人们对于自己的外貌要求越来越高&#xff0c;因此美颜相机、美妆相机等软件也逐渐兴起。其中&#xff0c;美妆相机是一种可以实现“快速上妆效果”的美颜工具&#xff0c;而美颜SDK则是实现美妆相机的核心技术之一。本文将介绍如何使用美颜SDK制作美…

你怎么看 App响应时间优化这事?

作者&#xff1a;xuexiangjys 响应时间&#xff0c;它是用来衡量系统运行效率的一个重要指标。评价一个应用的响应时间&#xff0c;可以从用户感知和系统性能这两个角度来考量。 响应时间的长短&#xff0c;可能影响用户对某个功能、某个应用、乃至某个系统的使用。毕竟如果有选…

VS2022配置OpenGL+GLAD

Glew&#xff08;The OpenGL Extension Wrangler Library&#xff09;是对底层OpenGL接口的封装&#xff0c;可以让你的代码跨平台。Glad与Glew作用相同&#xff0c;可以看作它的升级版。 Freeglut&#xff08;OpenGL Utility Toolkit&#xff09;主要用于创建并管理窗口和Ope…

Windows逆向安全(一)之基础知识(十五)

指针二 先前介绍了指针的一些基本的知识&#xff0c;但都没有提到地址的概念&#xff0c;下面承接之前的笔记&#xff0c;继续学习指针 下面要介绍三个相关的内容&#xff1a;获取变量的数据类型 、 取变量地址和取地址中存储的数据 获取变量的数据类型 在C语言中可以使用下…

Sleep:预测认知能力的最佳纺锤波检测参数

导读 目的&#xff1a;睡眠纺锤波的改变与认知障碍有关。这一发现增加了人们对识别基于睡眠的认知和神经退行性疾病生物标志物(包括睡眠纺锤波)的兴趣。然而&#xff0c;围绕纺锤波定义和算法参数设置的灵活性带来了方法上的挑战。本研究的目的是描述纺锤波检测参数设置如何影…

Dynamic Slicing for Deep Neural Networks

0、摘要 程序切片已广泛应用于各种软件工程任务中。然而&#xff0c;现有的程序切片技术只能处理由指令和变量构建的传统程序&#xff0c;而不能处理由神经元和突触组成的神经网络。在本文中&#xff0c;我们提出了 NNSlicer&#xff0c;这是第一种基于数据流分析的深度神经网络…

android studio shape形状图形

1.创建shape 2定义椭圆 <?xml version"1.0" encoding"utf-8"?> <shape xmlns:android"http://schemas.android.com/apk/res/android"android:shape"oval"><!--指定形状椭圆--><!--指定形状内部颜色--><…

Ubuntu与window实现文件共享——Samba使用

前言 &#xff08;1&#xff09;我们在使用Linux开发的时候&#xff0c;因为Linux中写程序没有Windows的工具方便&#xff0c;所以经常是先在windows环境下编写程序&#xff0c;之后再将文件上传给Linux进行编译。 &#xff08;2&#xff09;这样就存在一个问题&#xff0c;因为…

vue使用Howler实现音乐播放器

vue使用Howler实现音乐播放器 前言一、引入依赖二、封装组件 前言 本文使用Howler.js进行播放。使用siriwave做的播放动画具体文档地址如下 名称地址Howlerhttps://howlerjs.com/siriwavehttps://github.com/kopiro/siriwave 最后实现效果如下&#xff1a; 实现暂停、开始、…

教你如何根据需求编写测试用例,不用写一行代码,使用ChatGPT4自动完成。

首先来张效果图&#xff0c;需求我是放到requirements.txt文档里&#xff0c;输出的测试用例是放到test_case1.txt&#xff0c;整个代码我是让ChatGPT4自动给我写的。 我用的prompt提示语是&#xff1a; 我的想法是这样&#xff0c;通过Python代码&#xff0c;和API keys来实现…

传统制造企业在引入项目管理机制时项目组织结构的重要性

在传统的工业设备制造行业,针对以订单项目为驱动的业务模式,建立一套成熟完备的项目管理机制十分重要,同时也是企业提升自身管理水平精细度的内在要求。项目管理作为外企普遍应用的成熟管理模式,如何将其引入并与民企现存的传统职能型管理模式融合,实现成功嫁接,值得大家思考并…

AD9208之8通道高速采集

板卡概述 FMC168 是 一 款 基 于 VITA57.4 标 准 的2GSPS/2.6GSPS/3GSPS 采样率 14 位分辨率 Double FMC子卡模 块&#xff0c;该模块可以实现 8 路 14-bit、2GSPS/2.6GSPS/3GSPS 采样率模 拟信号采集。该板卡 ADC 器件采用 ADI 公司的 AD9208 芯片,该芯片 与 AD9689 完全…

快商通AI技术再获殊荣,荣膺厦门市“科学技术进步奖”

近日&#xff0c;快商通AI科研项目荣获厦门市“科学技术进步奖”&#xff0c;这是对快商通AI技术研究成果的高度肯定&#xff0c;也是快商通在人工智能领域的又一重大突破。 快商通作为一家技术领先的企业&#xff0c;始终坚持 核心技术自主研发 &#xff0c;致力于将自然语言…

【Linux命令行与shell脚本编程】 一,Shell简介

Linux命令行与shell脚本编程 第一章 Shell简介 目录 Linux命令行与shell脚本编程一,Shell简介1.1 终端(终端仿真器) 41.2 shell 提示符1.2.1 命令历史记录1.2.2 光标移动1.2.3 与 bash手册交互 命令的构成 一,Shell简介 1.1 终端(终端仿真器) 4 让用户访问 shell 使用图形用…

国产操作系统新机遇——小程序容器

信息技术应用创新不仅是各行各业实现数字转型的关键起点&#xff0c;而且还是我国加强网络安全和信息安全的重要手段。 现阶段&#xff0c;微软&#xff0c;谷歌和苹果等外国公司在操作系统市场上占据着几乎垄断的行业地位。国内操作系统行业正在努力改变过去过于分散的状态&a…

从FMCW毫米波雷达系统的性能参数理解4D成像毫米波雷达的设计思路

本文编辑&#xff1a;调皮哥的小助理 站在设计雷达的角度看&#xff0c;其实无论是传统的3D毫米波雷达&#xff0c;还是如今的4D毫米波成像雷达&#xff0c;其雷达系统性能参数都遵循一个原则&#xff0c;即&#xff1a; d res ⋅ v res ⋅ θ res d max ⁡ ⋅ v max ⁡ ⋅ …

全志v851s GPIO 应用程序编写

1. 查看硬件电路图SCH_Schematic1_2022-11-23 &#xff0c;查找合适的gpio 作为使用pin 在这里我们选取 GPIOH14&#xff08;注意目前开发使用这个pin 作为触摸屏的pin脚&#xff0c;需要将触摸屏connect断开&#xff09; &#xff0c;因为 可以通过排插使用杜邦线将其引出&am…

scala特质trait

目录 说明案例动态混入 说明 Scala 语言中&#xff0c;采用特质 trait&#xff08;特征&#xff09;来代替接口的概念&#xff0c;也就是说&#xff0c;多个类具有相同的特质&#xff08;特征&#xff09;时&#xff0c;就可以将这个特质&#xff08;特征&#xff09;独立出来…

rabbitMQ学习总结

RabbitMQ 生产者通过-》通道-》交换机-》投到消息队列-》再通过通道-》消费者 分布式架构 何谓分布式系统 通俗一点: 就是一个请求由服务器端的 多个服务 (服务或者系统)协同处理完成 和单体架构不同的是&#xff0c;单体架构是一个请求发起ivm调度线程(确切的是tomcat线程池)…