c语言用递归实现汉诺塔

Python017

c语言用递归实现汉诺塔,第1张

见代码注释,还有不懂可以问。

#include <stdio.h>

void move(char x,char y)

{

    printf("%c-->%c\n",x,y)

}

//hannuota函数的作用:把n个圆盘从one柱子借助two柱子放到three柱子 

void hannuota(int n,char one,char two,char three)

{

    if(n==1)//如果只有一个柱子 

        move(one,three)//直接移动即可 

    else

    {

        hannuota(n-1,one,three,two)//先把one柱子上的n-1个圆盘借助three柱子移动到柱子two 

        move(one,three)//把第一个柱子的剩下那一个(第n个)移动到第三个柱子

//由于原来one柱子上的n-1个圆盘已经移动到了two柱子上,因此不会有圆盘挡住n圆盘出来 

        hannuota(n-1,two,one,three)

        //最后再把那n-1个圆盘从two柱子借助one柱子移动到three柱子

//(上面第一句话hannuota(n-1,one,three,two)已经移动到了two柱子,因此这里是从two柱子移动到three柱子) 

    }

}

int main()

{

    int m

    printf("input the number of diskes:")

    scanf("%d",&m)

    printf("The step to move %d diskes:\n",m)

    hannuota(m,'A','B','C')

    return 0

}

一开始我接触汉诺塔也是很不解,随着代码量的积累,现在很容易就看懂了,因此楼主主要还是对递归函数的理解不够深刻,建议你多写一些递归程序,熟练了自己就能理解。

圆盘逻辑移动过程+程序递归过程分析

hanoi塔问题, 算法分析如下,设a上有n个盘子,为了便于理解我将n个盘子从上到下编号1-n,标记为盘子1,盘子2......盘子n。

如果n=1,则将“ 圆盘1 ” 从 a 直接移动到 c。

如果n=2,则:

(1)将a上的n-1(等于1)个圆盘移到b上,也就是把盘1移动到b上;

(2)再将a上 “盘2” 移到c上;

(3)最后将b上的n-1(等于1)个圆盘移到c上,也就是第(1)步中放在b上的盘1移动到c上。

注意:在这里由于超过了1个盘子,因此不能直接把盘子从a移动到c上,要借助b,那

么 hanoi(n,one,two,three)的含义就是由n个盘子,从one移动到three,如果n>2

那么就进行递归,如果n=1,那么就直接移动。

具体流程:

hanoi(2,a,b,c);由于2>1因此进入了递归的环节中。

<1>执行hanoi(1,a,c,b):这里就是刚才的步骤(1),代表借助c柱子,将a柱子上的 1个圆盘(盘1)移动到b柱子,其实由于是n=1,此时c柱子并没被用到,而是直接移动了。

<2>执行hanoi(1,a,b,c):这是步骤(2),借助b柱子,将a柱子上的一个圆盘(盘2)移动到c柱子上。这里由于也是n=1,也并没有真正借助b柱子,直接移动的。

<3>执行hanoi(1,b,a,c):这是步骤(3),将b上的一个盘子(盘1)移动到c

函数中由于每次调用hanoi的n值都是1,那么都不会进入递归中,都是直接执行了mov移动函数。

如果n=3,则:(倒着想会想明白)移动的倒数第二部,必然是下面的情况

(1)将a上的n`-1(等于2)个圆盘移到c上,也就是将盘1、盘2 此时都在b柱子上,只有这样才能移动最下面的盘子(盘3)。那么由于现在我们先忽略的最大的盘子(盘3),那么我们现在的目标就是,将两个盘子(盘1、盘2)从a柱子上,借助c柱 子,移动到b柱子上来,这个过程是上面n=2的时候的移动过程,n=2的移动过程是“2 个盘子,从柱子a,借助柱子b,移动到柱子c”。现在是“2个盘子,从柱子a,借助柱子 c,移动到柱子b上”。因此移动过程直接调用n=2的移动过程就能实现。

(2)将a上的一个圆盘(盘3)移到c。

(3)到这一步,由于已经将最大的盘子(盘3)移动到了目的地,此时无论后面怎么移动都不需要在用到最大的那个盘子(盘3),我们就先忽略他,剩下的目标就是将b上面的n-1个盘子(盘1、盘2)移动到c上,由于a上没有盘子了,此时要完成上面的目标,就要借助a盘子。最终达到的目标就是将b上的2个盘子,借助a移动到c上,这个过程就是当n=2时分析的过程了,仅仅是最开始的柱子(b柱子)和被借助的柱子(a柱子)不同了。所以直接调用n=2时候的过程就能股实现了。

具体执行过程:

hanoi(3,a,b,c);由于3>1因此进入了递归的环节中。

<1>执行hanoi(2,a,c,b):这里代表刚才的步骤(1),将两个盘子(盘1、盘2)从a移动到b,中间借助c。根据n=2的分析过程,必然是能够达到我们的目的。

<2>执行hanoi(1,a,b,c):现在a上只有一个盘子(盘3),直接移动到c上面即可。

<3>执行hanoi(2,b,a,c):此时对应步骤(3),剩下的目标就是将b上的两个盘子,借助a移动到c上。那么同样根据n=2的移动过程,必然能达到目的。

最终实现了3个盘子从a,借助b移动到了c。

这里没有运算,只是每一步都按照你最顶上的伪算法描述,按某个固定的顺序去递归调用所谓的搬移程序,注意关键不是搬移程序里面干什么(其实什么都不用干,算法分析而已),而是递归调用时的参数顺序。如果一定要干点什么,我自己当时也是觉得要干点什么,所以自己加上了个演示的东西,结果就真的干了点什么,给你看看吧(已通过dev c++ 5 编译执行)。

/*

Name: hanoi tower show

Copyright: whatever you want,i donn't care

Author: zero_fn

Date: 07-04-11 11:52

Description: first try of hanoi tower and stack OP

*/

#include <stdio.h>

#define UCHAR unsigned char

#define UINT32 unsigned int

#define CLS system("CLS")

/*share var define*/

UINT32 * A_top = NULL, * A_bottom = NULL, * B_top = NULL, * B_bottom = NULL, * C_top = NULL, * C_bottom = NULL

UINT32 steps = 0

/*function define*/

UINT32 * build_stack(UINT32 f)

UINT32 push(UINT32 ** top, UINT32 * bot, UINT32 f,UINT32 tmp)

UINT32 gettop(UINT32 ** top, UINT32 * bot)

UINT32 ptop(UINT32 ** top , UINT32 * bot)

void move(UINT32 **stop , UINT32 * sbot, UINT32 **dtop, UINT32 * dbot ,UINT32 f)

void show_stack(UINT32 f)

void Pan(UINT32 n, UINT32 f, UINT32 **topA, UINT32 *botA, UINT32 **topB, UINT32 *botB,UINT32 **topC, UINT32 *botC)

void delay(void)

{

UINT32 tmp = 3000

while(tmp)

tmp--

}

void hanoi(void)

{

UINT32 flo = 0, f = 0

puts("输入演示汉诺塔的层数 max 13:")

scanf("%d",&flo)

if(flo>13) f=13

else f = flo

A_top = build_stack(f)

B_top = build_stack(f)

C_top = build_stack(f)

if((NULL == A_top) || (NULL == B_top) || (NULL == C_top))

{

free(A_top)free(B_top)free(C_top)

return

}

else

{

A_bottom = A_top+f

B_bottom = B_top+f

C_bottom = C_top+f

for(flo = 0flo <fflo++)

{

*(A_top+flo) = 2*flo+1

}

B_top = B_bottom

C_top = C_bottom

}

CLS

show_stack(f)

puts("按任意键开始演示")

getch()

steps = 0

Pan(f, f, &(A_top), A_bottom, &(B_top), B_bottom, &(C_top), C_bottom)

printf("完成! 共搬移:\"%d\"次 任意键继续",steps)

getch()

}

void Pan(UINT32 n, UINT32 f, UINT32 **topA, UINT32 *botA, UINT32 **topB, UINT32 *botB,UINT32 **topC, UINT32 *botC)

{

/*递归调用,不断的搬盘子*/

if(1 == n)

{

move(topA, botA, topC, botC, f)

CLS

show_stack(f)

delay()

}

else

{

Pan(n-1, f, topA, botA, topC, botC, topB, botB)

move(topA, botA, topC, botC, f)

CLS

show_stack(f)

delay()

Pan(n-1, f, topB, botB, topA, botA, topC, botC)

}

}

void move(UINT32 **stop , UINT32 *sbot, UINT32 **dtop, UINT32 *dbot ,UINT32 f)

{

/*模拟搬移盘子的过程 */

UINT32 tmp

tmp = ptop(stop, sbot)

push(dtop, dbot, f, tmp)

steps++

}

UINT32 * build_stack(UINT32 f)

{

/* 建立堆栈 ,用于模拟放盘子的柱子*/

UINT32 * top

if(NULL == (top = (UINT32 *)calloc(f , sizeof(UINT32))))

return NULL

return top

}

UINT32 push(UINT32 **top,UINT32 * bot,UINT32 f,UINT32 tmp)

{

/*值压栈 把盘子放到某根柱子最上层*/

if(*top <=((bot-f)))

{

puts("stack overflow...")

return 0

}

(*top)-- //fix Top ADD

**top = tmp

return 1

}

UINT32 ptop(UINT32 **top ,UINT32 *bot)

{

/*取值出栈 把盘子从某根柱子上取下来*/

UINT32 tmp

if(*top == bot)

{

puts("stack underflow...")

return 0

}

tmp = **top

**top = 0

(*top)++ ////fix Top ADD

return tmp

}

UINT32 gettop(UINT32 ** top, UINT32 * bot)

{

/*取值不出栈*/

UINT32 tmp

if(*top == bot)

{

puts("stack underflow...")

return 0

}

tmp = **top

return tmp

}

void show_stack(UINT32 f)

{

/*显示各个柱子和上面盘子的情况*/

UCHAR buff[30] = {0}

UCHAR buff1[30] = {0}

UINT32 i,j,k

sprintf(buff1,"%26s","========================= ")

printf("%s",buff1)

printf("%s",buff1)

printf("%s\n",buff1)

for(i=1i<=fi++)

{

for(k=0k<((25-*(A_bottom-i))/2)k++)

{

buff[k] = ' '

}

for(j=0j<*(A_bottom-i)j++)

{

buff[j+k] = '*'

}

buff[j+k] = '\0'

sprintf(buff1,"%-25s",buff)

printf("%s",buff1)

//sprintf(buff1,"%-13s",buff)

//printf("%s",buff1)

printf(" ")

buff[0]='\0'

for(k=0k<((25-*(B_bottom-i))/2)k++)

{

buff[k] = ' '

}

for(j=0j<*(B_bottom-i)j++)

{

buff[j+k] = '*'

}

buff[j+k] = '\0'

sprintf(buff1,"%-25s",buff)

printf("%s",buff1)

//sprintf(buff1,"%-13s",buff)

//printf("%s",buff1)

printf(" ")

buff[0]='\0'

for(k=0k<((25-*(C_bottom-i))/2)k++)

{

buff[k] = ' '

}

for(j=0j<*(C_bottom-i)j++)

{

buff[j+k] = '*'

}

buff[j+k] = '\0'

sprintf(buff1,"%-25s",buff)

printf("%s",buff1)

//sprintf(buff1,"%-13s",buff)

//printf("%s",buff1)

puts(" ")

buff[0]='\0'

}

}

int main(int argc, char *argv[])

{

hanoi()

system("PAUSE")

}