汉诺塔的详细分析步骤及可视化程序

 三个柱子:  A, B, C
 盘子数:    n
 
 1. 通过整体思想,把n-1看为一个整体,目的显而易见
 	把  n-1    	 从   A   移到    B
 	把  最大的  	 从   A   移到    C
	把  n-1      从   B   移到    C
 
 2. 其中比较费解的就是:
        n-1如何从A移到B的
        n-1又是如何从B移到C的。
 
 3. 解释n-1如何从A移动B
 把  n-2     从   A   移到   C
 把  最大的   从   A   移到   B
 把  n-2     从   C   移到   B
 
 4. 解释n-1如何从B移动C
 把  n-2     从   C   移到  A
 把  最大的   从   C   移到  B
 把  n-2     从   A   移到  B
 
 1的步骤可以看作是 从A移到C
 3的步骤可以看作是 从B移到A
 4的步骤可以看作是 从C移到B
 
 根据这些我们可以建立通用的函数:
 move(int nNumb, string strFrom, string strTo);
 参数:    nNumb       移动个数
         strFrom     从哪移动
         strTo       移到哪去
 
 
 问题就可以概括为:
                                         { move(n-2, "A", "C")
                   { move(n-1, "A", "B") { move(1,   "A", "B")
                   {                     { move(n-2, "C", "B")
 move(n, "A", "C") { move(1,   "A", "C")                            ...
                   {                     { move(n-2, "B", "A")
                   { move(n-1, "B", "C") { move(1,   "B", "C")
                                         { move(n-2, "A", "C")
 
 
 由上又可以看出部分结构的组成,通过这部分结构,可以看出这就是一个递归体:
 
                     { move(n-1, Begin, Other)
 move(n, Begin, End) { move(1,   Begin, End  )
                     { move(n-1, Other, End  )
 
 那么递归的终止条件在哪呢?我们按照这个步骤推演到最后,结构类似如下:
 
                     { move(1, Begin, Other)
 move(2, Begin, End) { move(1, Begin, End  )
                     { move(1, Other, End  )
 
 显而易见的,move(1, ..., ...);没有再执行下去的必要。 所以这也就成为了递归的终止条件。

代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <tchar.h>

using std::max_element;
using std::cout;
using std::endl;
using std::vector;
using std::string;

static int nStep = 0;

struct HanNuoTa
{
	string strName;			// 塔名
	vector<int> vecData;	// 塔内数据
};

HanNuoTa GetTaByName(const string & strName, const HanNuoTa& A, const HanNuoTa& B, const HanNuoTa& C)
{
	if (strName.compare(A.strName) == 0)
	{
		return A;
	}
	else if (strName.compare(B.strName) == 0)
	{
		return B;
	}
	else if (strName.compare(C.strName) == 0)
	{
		return C;
	}
}

void PrintData(const HanNuoTa& A, const HanNuoTa& B, const HanNuoTa& C)
{
	int nNumb[] = { A.vecData.size(), B.vecData.size(), C.vecData.size() };
	int nMax = *max_element(nNumb, nNumb + 3);

	if (nStep == 0)
	{
		cout << "开始:" << endl;
	}
	else
	{
		cout << "第" << nStep << "步" << endl;
	}
	
	cout << "A" << "\tB" << "\tC" << endl;
	nStep++;

	HanNuoTa ATemp = GetTaByName("A", A, B, C);
	HanNuoTa BTemp = GetTaByName("B", A, B, C);
	HanNuoTa CTemp = GetTaByName("C", A, B, C);

	for (int i = 0; i < nMax; i++)
	{
		cout << (ATemp.vecData.size() > i ? ATemp.vecData.at(i) : 0) << "\t";
		cout << (BTemp.vecData.size() > i ? BTemp.vecData.at(i) : 0) << "\t";
		cout << (CTemp.vecData.size() > i ? CTemp.vecData.at(i) : 0) << endl;
	}

	cout << endl;
}

void Move(const int nNumb, HanNuoTa& stuFrom, HanNuoTa& stuTo)
{
	stuTo.vecData.insert(stuTo.vecData.begin(), stuFrom.vecData.begin(), stuFrom.vecData.begin() + nNumb);
	stuFrom.vecData.erase(stuFrom.vecData.begin(), stuFrom.vecData.begin() + nNumb);
}

//**************************************************
//	@参数:nNumb	移动数量
//		   A		开始移动的塔
//		   B		途径的塔
//		   C		结束的塔
//**************************************************
void HanNuo(const int nNumb, HanNuoTa& A, HanNuoTa& B, HanNuoTa& C)
{
	if (nNumb == 1)
	{
		Move(nNumb, A, C);
		PrintData(A, B, C);
	}
	else
	{
		HanNuo(nNumb - 1, A, C, B);
		HanNuo(1, A, B, C);
		HanNuo(nNumb - 1, B, A, C);
	}
}

int main(int argc, const char* argv[])
{
	HanNuoTa A, B, C;
	A.strName = "A";
	A.vecData = { 1, 2, 3 };

	B.strName = "B";
	C.strName = "C";

	PrintData(A, B, C);
	HanNuo(A.vecData.size(), A, B, C);
}

测试结果:
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个用 C++ 编写的汉诺塔可视化程序: ```cpp #include <iostream> #include <graphics.h> #include <conio.h> using namespace std; void drawPillar(int x, int y, int height, int width) { setfillcolor(BROWN); solidrectangle(x - width / 2, y, x + width / 2, y + height); } void drawDisk(int x, int y, int width, int height) { setfillcolor(YELLOW); solidrectangle(x - width / 2, y, x + width / 2, y + height); } void moveDisk(int from, int to, int n, int height, int width) { int x1 = 100 + from * 200, x2 = 100 + to * 200; int y = 400 - height * n; for (int i = y; i >= 100; i -= 10) { clearrectangle(x1 - width / 2, i, x1 + width / 2, i + height); drawPillar(x1, 400, height, width); if (from < to) { drawPillar(x2, 400, height, width); drawDisk(x2, i, 50 + n * 10, height); } drawDisk(x1, i, 50 + n * 10, height); Sleep(100); } for (int i = x1; i != x2; i += (x2 - x1) / abs(x2 - x1)) { clearrectangle(i - width / 2, 100, i + width / 2, y + height); drawPillar(x1, 400, height, width); if (from < to) { drawPillar(x2, 400, height, width); drawDisk(x2, y, 50 + n * 10, height); } drawDisk(i, y, 50 + n * 10, height); Sleep(100); } for (int i = y + 10; i <= 400 - height * (n - 1); i += 10) { clearrectangle(x2 - width / 2, i - 10, x2 + width / 2, i + height); drawPillar(x1, 400, height, width); if (from < to) { drawPillar(x2, 400, height, width); drawDisk(x2, i, 50 + n * 10, height); } drawDisk(x2, i, 50 + n * 10, height); Sleep(100); } } void hanoi(int from, int to, int via, int n, int height, int width) { if (n == 0) return; hanoi(from, via, to, n - 1, height, width); moveDisk(from, to, n, height, width); hanoi(via, to, from, n - 1, height, width); } int main() { initgraph(800, 600); drawPillar(100, 400, 200, 20); drawPillar(300, 400, 200, 20); drawPillar(500, 400, 200, 20); hanoi(0, 2, 1, 5, 20, 150); getch(); closegraph(); return 0; } ``` 该程序使用了 EasyX 图形库,可以在 Windows 系统下运行。在程序中,我们使用了 `drawPillar()` 函数来绘制柱子,使用 `drawDisk()` 函数来绘制盘子,使用 `moveDisk()` 函数来移动盘子。其中,`moveDisk()` 函数使用了 `Sleep()` 函数来控制动画播放速度。 在程序的 `main()` 函数中,我们首先初始化图形库,并绘制出三个柱子。然后,我们调用 `hanoi()` 函数来执行汉诺塔的移动操作。在 `hanoi()` 函数中,我们首先将前 `n-1` 个盘子从起始柱移动到中间柱,然后将最后一个盘子从起始柱移动到目标柱,最后将前 `n-1` 个盘子从中间柱移动到目标柱。在每次移动操作中,我们调用 `moveDisk()` 函数来实现盘子的平滑移动效果。 运行程序后,可以看到汉诺塔的移动动画。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值