7-17 汉诺塔的非递归实现 (25 分)(C语言版)

7-17 汉诺塔的非递归实现 (25 分)

问题描述:

借助堆栈以非递归(循环)方式求解汉诺塔的问题(n, a, b, c),即将N个盘子从起始柱(标记为“a”)通过借助柱(标记为“b”)移动到目标柱(标记为“c”),并保证每个移动符合汉诺塔问题的要求。

输入格式:

输入为一个正整数N,即起始柱上的盘数。

输出格式:

每个操作(移动)占一行,按柱1 -> 柱2的格式输出。

输入样例:

3

输出样例:

a -> c
a -> b
c -> b
a -> c
b -> a
b -> c
a -> c

提交结果

在这里插入图片描述

分析

  • 本题我本是没有思路的,并不是很懂汉诺塔的算法逻辑,查阅一部分资料以后,大致明白了算法怎样进行,但是原理还不是很清楚,大家可以参考汉诺塔算法
  • 看完以后,还是为了图方便,我用了python写代码,但是,写完以后,发现最后一组测试数据超时(python的硬伤),我尽力进行了优化,但是还是超时,没办法,决定用C语言写。
  • 看了看网上的代码,大多都是C++写的,奈何我菜,没学过,看不懂,只能一比一把我python代码修改成了C的代码,最后也是通过了测试。

代码

#include<stdio.h>
#include<string.h>

void move(int pos1, int data[3][30], int pos2, char l[], int pos[])
{
    int b = data[pos1][pos[pos1]];   //获取两个柱子顶部元素
    int c = data[pos2][pos[pos2]];
    if ((b < c || c == 0) && b != 0) {   //第一个柱子小,或者第二个柱子空时,将第一个柱子顶部盘子转移到第二个
        data[pos2][++pos[pos2]] = b;
        pos[pos1]--;
        printf("%c -> %c\n", l[pos1], l[pos2]);
    }
    else if ((b > c || b == 0) && c != 0) {  //原理同上
        data[pos1][++pos[pos1]] = c;
        pos[pos2]--;
        printf("%c -> %c\n", l[pos2], l[pos1]);
    }
}

int main()
{
    int pillars[3][30] = { 0 }, i, pos[3] = { 0 }, n, pos_key = 0;  //储存三个柱子上面的盘子序号、三个柱子的最后一个元素的位置、‘1’号盘子所在的位置
    char str[10];   //三个柱子的代号
    scanf("%d", &n);
    strcpy(str, n % 2 ? "acba" : "abca");  //偶数abc;奇数acb
    int flag = 2 - n % 2;  //根据输入的奇偶判断目标柱子的位置
    for (i = 0; i < n; i++)
        pillars[0][i + 1] = n - i;
    pos[0] = n;    //初始化‘a’柱
    while (n != 0) {   //输入0时不做任何输出
        printf("%c -> %c\n", str[pos_key], str[pos_key + 1]);  //转移‘1’盘子
        pos[pos_key]--;   //存放‘1’的柱子计数减一
        pos_key = (pos_key + 1) % 3;   //‘1’的位置加一,并取余防止溢出
        pillars[pos_key][++pos[pos_key]] = 1;  //被转移柱子计数加一
        if (pos[flag] == n) break;    //如果目标柱子已经摆满所有盘子,即达到目标,停止循环
        int p1 = (pos_key + 1) % 3, p2 = (pos_key + 2) % 3;
        move(p1, pillars, p2, str, pos);  //将除‘1’所在柱子外的两个柱子的顶部最小的盘子转移到另一个柱子
    }
    return 0;
}

另附:

(把python代码也贴一贴吧,想看的可以看一下)

def move(pos1, data, pos2, l):
    x1, x2 = l[pos1], l[pos2]
    b = data[pos1][len(data[pos1])-1]
    c = data[pos2][len(data[pos2])-1]
    if (b < c or c == 0) and b != 0:
        data[pos2].append(data[pos1].pop())
        print(x1,"->",x2)
    elif (b > c or b == 0) and c != 0:
        data[pos1].append(data[pos2].pop())
        print(x2,"->",x1)

n = int(input())
pillars = [[0],[0],[0]]
l = ['a','b','c','a']
for i in range(n):
    pillars[0].append(n-i)
if n%2 == 1:
    l = ['a','c','b','a']

flag = 2 - n%2
pos_1 = 0

while n != 0:
    pillars[pos_1].remove(1)
    print(l[pos_1], "->", l[pos_1+1])
    pos_1 = (pos_1+1)%3
    pillars[pos_1].append(1)
    if len(pillars[flag]) - n-1 == 0:
        break
    move((pos_1+1)%3, pillars, (pos_1+2)%3, l)

由于是同样的方法,我就不给python代码注释了。

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谛凌

本人水平有限,感谢您支持与指正

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值