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

来源:互联网 发布:iope神仙水怎么用 知乎 编辑:程序博客网 时间:2024/04/30 05:53

第二个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 );

0 0
原创粉丝点击