3.1 汉诺塔问题

文章介绍了汉诺塔问题的解决思路,使用递归算法将问题分解为移动较小盘子到辅助柱和移动最底层盘子到目标柱。通过代码示例展示了3个盘子的移动过程,并通过内存追踪探讨了递归工作栈的概念,解释了参数地址相同的原因。最后分析了该问题的时间复杂度为O(2^n)和空间复杂度为O(n)
摘要由CSDN通过智能技术生成

一.问题引入

简单来说,汉诺塔问题有以下几个要求:

1.有A,B,C三根柱子,在A柱上有n个大小逐渐变大的盘子,我们现在要把A柱上的所有盘子移到C柱上。同时要遵循以下两点要求。

2.一次只能移动一个盘子。

3.无论何时,小的盘子必须在大的盘子上面。

下面是3个盘子的初始状态,我也将展示3个盘子的代码

二.解决思路

从逻辑的角度来看,我们要将这个问题进行分层,得出最重要的两步:

1.移开除了最底层的盘子以外的盘子

2.移动最底层的盘子

于是我们能够解析出一个移动通式

if(n==1)直接移动

else {

step 1 将上方的n-1个盘子移动到辅助塔(非起始塔和目标塔)

step 2 移动最底层的盘子到目标塔

step 3 将移走的n-1个盘子移到目标塔

}

而这其中n-1盘子的移动方法使用递归的思想来实现

代码如下

#include <stdio.h>

/**
 * Hanoi
 */
void hanoi(int paraN, char paraSource, char paraDestination, char paraTransit) {
    if (paraN <= 0) {
        return;
    } else {
        hanoi(paraN - 1, paraSource, paraTransit, paraDestination);
        printf("%c -> %c \r\n", paraSource, paraDestination);
        hanoi(paraN - 1, paraTransit, paraDestination, paraSource);
    }// Of if
}// Of hanoi

/**
 * Test the hanoi function
 */
void hanoiTest() {
    printf("---- addToTest begins ----\r\n");

    printf("2 plates\r\n");
    hanoi(2, 'A', 'B', 'C');

    printf("3 plates\r\n");
    hanoi(3, 'A', 'B', 'C');

    printf("---- addToTest ends ----\r\n");
}// Of addToTest

/**
 The entrance
 */
void main() {
    hanoiTest();
}// Of main

说明:这里的移动在计算机内部并没有进行,仅仅是用输出语句告诉我们在逻辑上进行了移动,读者可以自行去用程序设计语言去实现物理的移动。

逻辑流程图

三.内存追踪

我们将函数变为这样

void hanoi(int paraN, char paraSource, char paraDestination, char paraTransit) {
    if (paraN <= 0) {
        return;
    } else {
        printf("the address of paraN: %ld, paraSource: %ld, paraTransit :%ld\n",&paraN,&paraSource,&paraTransit);
        hanoi(paraN - 1, paraSource, paraTransit, paraDestination);
        printf("%c -> %c \r\n", paraSource, paraDestination);
        hanoi(paraN - 1, paraTransit, paraDestination, paraSource);
    }// Of if
}// Of hanoi

在每次进行函数调用的时候进行对其中参数的地址打印,进行对地址的追踪。

下图为结果

 我们研究plate= 2 的部分

the address of paraN: -1191183088, paraSource: -1191183080, paraTransit :-1191183064
the address of paraN: -1191183136, paraSource: -1191183128, paraTransit :-1191183112
A -> C 

A -> B

the address of paraN: -1191183136, paraSource: -1191183128, paraTransit :-1191183112
C -> B 

发现这个有两个函数的空间的参数地址是相同的,此时这两个函数在执行什么呢?

首先是第二行地址打印,这时的paraN为1,在打印出A->C的时候Hanoi(1)就已经结束了

然后是最后一行地址打印,这时的paraN为1,而在此时的参数占用地址跟上一句时一样的,为何?

这时我们就要提出一个概念叫做“递归工作栈”的概念了。

四.递归工作栈

在刚才的函数中我你能够看出在paraN=2时候的函数在工作还未进行完成时,这时又进行了paraN=1 的函数,根据函数的工作原理,在进行paraN=2 的时候,计算机已经给这个函数分配了一片的地址了,在进行到paraN的时候,我们又要分配一片空间去给paraN=1 这个函数去进行使用,在完成后,释放这片空间,进行移动操作,然后再次执行paraN=1,这时又使用了刚才的空间,这是因为递归的工作是以栈的形式完成的。

因为在执行函数中的函数的时候,我们怎么去保存上一级递归的数据呢?

我们首先要执行paraN=2,紧接着我们就要执行paraN=1,把paraN=2 的数据压入栈中。

paraN=1中又执行paraN=0,又将paraN=1 的参数列表压入栈中。

 而后如果函数执行完成,比如,paraN=0,直接进行了return,此时就要将paraN=1从栈中弹出,继续进行函数的执行。

 五.时间复杂度和空间复杂的分析

通过上图示,可易知空间复杂度为O(n)

而时间复杂度,比如Hanoi(2).

T(n)=T(n-1)+ 1

T(1)= 1

可解得时间复杂度为O(2的n次方)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值