您的位置:首页 > 编程语言 > C语言/C++

c语言汉诺塔演示程序设计(基于堆栈、递归)

2013-12-24 12:44 471 查看
第二个c语言课程设计,看到这个题目的时候有些迷茫,没有头绪,但是在网上看到了一个实现的范例之后,有了些思路,第一次写的时候结果总是按照之前看的范例的思路,但又不能领会他人思路的精髓,始终不得要领。

昨天决定自己按照自己的思路,自己设计数据结构,实现目标,晚上在床上构思了十来分钟。今早起床根据昨晚的构思两个小时左右就写完了整个小程序,主要源于思路清晰,且程序本身内容不多,主要是关于堆栈数据结构的运用和递归思想的实践,总共不到200行.

//C语言写的汉诺塔(10层以下)动画演示小程序

#include<stdio.h>   

#include<stdlib.h>   

#include<conio.h>   

#include<string.h>   

#include<Windows.h> 

#include<malloc.h>

 

//宏定义9层汉诺塔

#define LEN 9         

//每个柱子的结构

typedef>int>int>int>COORD>
//每一个element对应一个pos值,坐标

}stack,*pstack;

//函数声明

void InitStack(pstack ,int );

void Push(pstack ,int );

int Pop(pstack ); 

void PrintStack(pstack );

void Hanoi(pstack ,pstack ,pstack ,int  );

void> //记录汉诺塔移动步数

int>//设置内部变量
int i;
HANDLE hOutput;
COORD pos;
stack st[3];
pstack a,b,c;
a = st;
b = st+1;
c = st+2;

//初始化三个栈为空, 且初始化栈元素显示坐标的x值
InitStack(a,5);     
InitStack(b,15);
InitStack(c,25);

//给a栈赋初值,栈低到栈顶依次为9-1
for(i=1;i<=LEN;i++)
{
Push(a,10-i);    
}

//显示三个柱子初始情况
PrintStack(a);
PrintStack(b);
PrintStack(c);
pos.X = 1;
pos.Y = 9;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput,pos);
printf("    A         B         C");

//开始汉诺塔移动
pos.X = 5;
pos.Y = 11;
SetConsoleCursorPosition(hOutput,pos);
printf("输入移动的汉诺塔层数:");
scanf("%d",&i);
getchar();
//屏蔽输入
Hanoi(a,b,c,i);
//把a的i层通过b移动到c

return 0;

}

//初始化函数,初始化内容:栈长、栈顶指针、栈元素显示位置

void InitStack(pstack ps,int x)

{
int i;
ps->max = LEN;
ps->top = -1;
for(i=0;i<LEN;i++)
{
ps->pos[LEN-1-i].X = x;
ps->pos[LEN-1-i].Y = i;
}

}

//将x压入栈sp

void Push(pstack sp,int x)

{
if(>
{
printf("ERROR!the stack is full,can't push!\n");
getchar();
return;
}
else
{
sp->top++;
sp->element[sp->top] = x;
}

}

//将栈sp栈顶元素出栈返回

int Pop(pstack sp)

{
if(sp->top >= 0)
{
return sp->element[sp->top--];
}
else
{
printf("ERROR!the stack is empty,can't pop!\n");
getchar();
return -1;
}

}

//按照堆栈显示位置打印堆栈

void PrintStack(pstack sp)

{
int i;
HANDLE hOutput;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
for(i=0;i<=sp->top;i++)
{
SetConsoleCursorPosition(hOutput,sp->pos[i]);
printf("%d",sp->element[i]);
}

}

//汉诺塔递归移动过程

void Hanoi(pstack x,pstack y,pstack z,int i)

{
if(i == 1)
{
move(x,z,x,y,z);
}
if(i == 2)
{
move(x,y,x,y,z);
move(x,z,x,y,z);
move(y,z,x,y,z);
}
else
{
Hanoi(x,z,y,i-1);
move(x,z,x,y,z);
Hanoi(y,x,z,i-1);
}

}

//每一次移动的操作

void move(pstack j,pstack k,pstack a,pstack b,pstack c)

{
HANDLE hOutput;
COORD pos;
pos.X = 3;
pos.Y = 12;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

Push(k,Pop(j));
step++;

//显示三个柱子移动后的情况
PrintStack(a);
PrintStack(b);
PrintStack(c);

pos.X = 1;
pos.Y = 9;
SetConsoleCursorPosition(hOutput,pos);
printf("    A         B         C");
pos.X = 5;
pos.Y = 12;
SetConsoleCursorPosition(hOutput,pos);
printf("当前移动的步数为:%d \n",step);

getchar();
system("CLS");

}

总结:

1、对于数据结构的选择,我采用的是浪费些许空间,建立栈的元素为静态数组。也有的实现使用动态数组,虽然节省了空间,但是算法较为繁琐,

//定义栈
typedef struct
{
ElementType *pbuffer;
int max;
int top;
}Stack;
typedef struct
{
Stack * sp[3];
int x[3];
int y;
int total;
}Hannuota;

测试证明:确实不用设置p_a、p_b、p_c三个参数,这样设置函数即可(代码中的设计设想上防止hanoi函数会置换move中的输出,但是事实上因为move中的输出每个堆栈都有自己的pos元素固定位置,所以不会影响柱子输出格式)
void Hanoi(pstack ,pstack ,pstack ,int  );void move(pstack ,pstack ,pstack ,pstack ,pstack );
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: