day27

Day 27 —— Hanoi

1. Background

今天是学习java的第27天,学习的内容是hanoi。

由于最近毕业设计业务繁忙,所以不得已中断了一些天的代码学习。现在补上,我的计划是在群里的群友复试之前学到第50天,也就是把数据结构的内容学完,然后专心去复习初试。

2. Description

2.1 Hanoi

汉诺塔作为我们的老朋友了,每一次学习新的计算机语言,每次讲递归老师都会讲一遍这个。

我对它的理解是有三根签签,第一根签签上串很多盘盘,大的在下,小的在上。我们的最终目标是把第一根签签上的盘盘全部移到最后一根上面去,移动过程中也要遵循大的在上小的在下规则。

2.2 操作

这个我讲一下我的思路吧,之前学C语言的时候被这个虐了好几天,把当时老师讲的每一个字都记得清清楚楚。

由于闵老师这里只用了三个盘盘,可能不具有代表性。我现在要讲思路嘛,直接极端一点,拿64个盘盘来举例(当年给我讲C语言的那个老师就是拿的64个盘)。

首先对于汉诺塔的玩法可以简单分为三个步骤:

  1. 将第一根签签上63个盘盘从X移动到Y上,确保大盘在小盘下。(为了叙述方便直接把第一个盘盘命名为X,第二个命名为Y,第三个为Z)
  2. 将X上面剩下的那个第64个盘子移到Z上。
  3. 将Y上的63个盘盘移到Z上。

好的,我们现在就把64个盘的问题转为了63个盘的问题,所以我们把这个思路聚集为下面的两个问题:

  1. 如何将X上的63个盘盘移到Y上。(通过Z)
  2. 如何将Y上的63个盘移到Z上。(通过X)

然后我们来讨论第一个问题:

  1. 将X上62个盘盘从X移动到Z上,确保大盘在小盘下。
  2. 将X上面剩下的那个第63个盘子移到Y上。
  3. 将Z上的62个盘盘移到Z上。

第二个问题同上:

  1. 将Y上62个盘盘从Y移动到X上,确保大盘在小盘下。
  2. 将Y上面剩下的那个第63个盘子移到Z上。
  3. 将X上的62个盘盘移到Z上。

这么分析下来递归的味道就出来了。下面直接进入代码。

3. Code

package datastructure;

/**
 * Hanoi tower.
 * 
 * @author Leo liu.
 */

public class Hanoi {

    /**
     ***********
     * 汉诺塔主体代码
     * 
     * @param paraFirst  第一根签签。
     * @param paraMiddle 第二根签签。
     * @param paraLast   第三根签签。
     * @param paraNum    盘子的数量。
     *                   **********
     */
    public static void hanoi(char paraFirst, char paraMiddle, char paraLast, int paraNum) {
        if (paraNum == 1) {
            System.out.println(paraFirst + "->" + paraLast + " ");
            return;
        }

        hanoi(paraFirst, paraLast, paraMiddle, paraNum - 1);
        System.out.println(paraFirst + "->" + paraLast + " ");
        hanoi(paraMiddle, paraFirst, paraLast, paraNum - 1);
    } // Of hanoi

    public static void main(String[] args) {
        hanoi('a', 'b', 'c', 3);
    } // Of main
} // Of Hanoi

运行结果:

在这里插入图片描述

4. Summarize

可能是之前学习汉诺塔的时候递归的思想深入我心了吧,二叉树反而没有什么感觉了。下去还得继续琢磨。

对于这个我特地把我两年前学习C语言的代码翻了出来,可惜的是电脑重装系统之后已经没有C语言编译环境了,所以没有运行查看结果。

#include <stdio.h>

#define MAX_NUM 64

int schedule[MAX_NUM+1][MAX_NUM+1];

int arrange(int begin, int num);

int arrange(int begin, int num)
{
        int i, j;

        if (num == 2)
        {
                schedule[begin][1] = begin;
                schedule[begin][2] = begin + 1;
                schedule[begin+1][1] = begin + 1;
                schedule[begin+1][2] = begin;
                return 0;
        }

        arrange(begin, num/2);
        arrange(begin + num/2, num/2);

        for (i = begin + num/2; i < begin + num; i++)
        {
                for (j = num/2 + 1; j <= num; j++)
                {
                        schedule[i][j] = schedule[i-num/2][j-num/2];
                }
        }

        for (i = begin; i < begin + num/2; i++)
        {
                for (j = num/2 + 1; j <= num; j++)
                {
                        schedule[i][j] = schedule[i+num/2][j-num/2];
                }
        }
}


int main(void)
{
        int num, i, j,flag = 1;
        char name[][128] = {0};

        printf("请输入参赛的队伍数量:");
        scanf("%d", &num);

        for(int i = 0; i < num; i++)
        {
        	printf("请输入第%d个队名", i + 1);
			scanf("%s", &name[i]);
			getchar();
		}
		
		// 检查num是否2的N次方
        // 注意,这里是&,不是&&
        // &是按位与操作,1&1==1,0&1==0,0&0 == 0
        if (num & num - 1)
        {
                printf("参数队伍的数量必须是2的N次方!\n");
                return -1;
        }

        arrange(1, num);

        printf("编 号");

        for (i = 1; i < num; i++)
        {
                printf("\t第%d天", i);
        }

        putchar('\n');

        for (i = 1; i <= num; i++)
        {
                for (j = 1; j <= num; j++)
                {
                        printf("%s\t", *(name + schedule[i][j] - 1));
                }
                putchar('\n');
        }

        return 0;
}

对了,这里说一下。代码中的提示词和注释最好还是用英文,用中文的很有可能会出现乱码。下图是我用VScode打开的画面,我猜想是我之前学习C语言的编译器的编码和VScode的不同,然后把文件用记事本打开,由于记事本有自动选取编码的功能,所以成功的看到了上面没有乱码的代码。

记事本上的编码显示的是ANSi,然后VScode默认是UTF-8的,所以出现了乱码。

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值