基于栈的c语言迷宫问题与实现 (2)

基于栈的c语言迷宫问题与实现 (2)
基于栈的c语言迷宫问题与实现 (2)

数据结构与算法实验报告

基于栈的C语言迷宫问题与实现

一.问题描述

多年以来,迷宫问题一直是令人感兴趣的题目。实验心理学家训练老鼠在迷宫中寻找食物。许多神秘主义小说家也曾经把英国乡村花园迷宫作为谋杀现场。于是,老鼠过迷宫问题就此产生,这是一个很有趣的计算机问题,主要利用“栈”是老鼠通过尝试的办法从入口穿过迷宫走到出口。

迷宫只有两个门,一个叫做入口,另一个叫做出口。把一只老鼠从一个无顶盖的大盒子的入口处赶进迷宫。迷宫中设置很多隔壁,对前进方向形成了多处障碍,在迷宫的唯一出口处放置了一块奶酪,吸引老鼠在迷宫中寻找通路以到达出口。求解迷宫问题,即找出从入口到出口的路径。

一个迷宫可用上图所示方阵[m,n]表示,0表示能通过,1 表示不能通过。现假设耗子从左上角[1,1]进入迷宫,编写算法,寻求一条从右下角[m,n] 出去的路径。下图是一个迷宫的示意图:

入口

出口

迷宫示意图

二.算法基本思想

迷宫求解问题是栈的一个典型应用。基本算法思想是:在某个点上,按照一定的顺序(在本程序中顺序为上、右、下、左)对周围的墙、路进行判断(在本程序中分别用1、0)代替,若周围某个位置为0,则移动到该点上,再进行下一次判断;若周围的位置都为1(即没有通路),则一步步原路返回并判断有无其他通路,然后再次进行相同的判断,直到走到终点为止,或者确认没有任何通路后终止程序。

要实现上述算法,需要用到栈的思想。栈里面压的是走过的路径,若遇到死路,则将该位置(在栈的顶层)弹出,再进行下一次判断;若遇到通路,则将该位置压栈并进行下一次判断。如此反复循环,直到程序结束。此时,若迷宫有通路,则栈中存储的是迷宫通路坐标的倒序排列,再把所有坐标顺序打印后,即可得到正确的迷宫通路。

三.程序具体部分的说明

1.迷宫的生成

根据题目的要求,迷宫的大小是自定义输入的。所以在程序中用malloc申请动态二维数组。数组中的元素为随机生成的0、1。数组周围一圈的元素全部定义为1,以表示边界。

2.栈的C语言实现

为了实现栈的功能,即清空、压栈、弹出、返回栈顶元素,在程序中编写了相应的函数。

MakeNULL 清空栈

Push 将横、纵坐标压栈

Topx 返回栈顶存储的横坐标

Topy 返回栈顶存储的纵坐标

Pop 弹出栈顶元素

3.具体的判断算法

当位置坐标(程序中为X Y)移到某一位置时,将这个位置的值赋值为1并压栈,以说明该点已经走过。接着依次判断该点的上、右、下、左是否为0,若有一方为0,则移动到该位置上,进行下次判断;若为周围位置全部是1,则将该点压栈后不断弹出,每次弹出时判断栈顶元素(即走过的路)周围有无其他通路。如果有的话,则选择该方向继续走下去;如果栈已经为空仍然没有找到出路,则迷宫没有出口程序结束。

当X Y走到出口坐标时,程序判断部分结束。栈里面存储的是每个走过的点的坐标,将这些横纵坐标分别存储在两个数组中,最后将数组中的坐标元素倒序输出,即得到了完整的路径。

四.程序源代码及注释

// Maze.cpp : 定义控制台应用程序的入口点。

//

#include"stdafx.h"

#include

#include

#include

#include

#include

typedef int Elementtype;

struct node

{

Elementtype val1;

Elementtype val2;

node *next;

};//定义结构体

typedef node *MAZE;

void MakeNull(MAZE &S);

void Push(Elementtype x,Elementtype y, MAZE S); void Pop(MAZE S);

Elementtype Topx(MAZE S);

Elementtype Topy(MAZE S);//申明函数

int _tmain(int argc, _TCHAR* argv[])

{

int **p,*q,*x1,*y1,i,j,k,n1,n2,m1,m2,l,w,max;

int x,y;

int a,b,c,d;

printf("输入迷宫长度及宽度l和w\n");

scanf("%d %d",&l,&w);

getchar();

n1=w+2;

n2=l+2;//为迷宫加上边界

max=n1*n2;

p=(int**)malloc(n1*sizeof(int));

for(i=0;i

p[i]=(int *)malloc(n2*sizeof(int));//生成二维动态数组

srand(time(NULL));

x1=(int*)malloc(max*sizeof(int));//生成动态数组用于存储路径y1=(int *)malloc(max*sizeof(int));//生成动态数组用于存储路径for(i=0;i

{

x1[i]=0;

}

for(i=0;i

{

y1[i]=0;

}//先将存储路径的数组元素全赋值为0

for(i=0;i

{

for(j=0;j

{

if(i==0 || j==0)

{

p[i][j]=1;

}

else if(i==n1-1 || j==n2-1)

{

p[i][j]=1;

}

else

p[i][j]=rand()%2+0;

}

}//生成二维1 0随机数组

p[1][1]=0;

p[n1-2][n2-2]=0;//定义迷宫的入口及出口

printf("生成的迷宫如下(代表墙0代表路):\n");

for(i=0;i

{

{

for(j=0;j

printf("%2d",p[i][j]);

}

printf("\n");

}//打印迷宫

MAZE S;

MakeNull(S);//清空栈

i=1;

j=1;

if(p[1][2]==1 && p[2][1]==1)

{

printf("There is no way out");a

getchar();

return 0;

}//判断入口是否就是死路

else

{

do

{

if(p[i-1][j]==0)

{

x=i;

y=j;

Push(x,y,S);

p[i][j]=1;

i=i-1;

}//判断能否向上走

else if(p[i-1][j]==1 && p[i][j+1]==0)

{

x=i;

y=j;

Push(x,y,S);

p[i][j]=1;

j=j+1;

}//判断能否向右走

else if(p[i-1][j]==1 && p[i][j+1]==1 && p[i+1][j]==0) {

x=i;

y=j;

Push(x,y,S);

k=Topx(S);

p[i][j]=1;

i=i+1;

}//判断能否向下走

else if(p[i-1][j]==1 && p[i][j+1]==1 && p[i+1][j]==1 && p[i][j-1]==0)

{

x=i;

y=j;

Push(x,y,S);

p[i][j]=1;

j=j-1;

}//判断能否向左走

else if(p[i-1][j]==1 && p[i][j+1]==1 && p[i+1][j]==1 && p[i][j-1]==1)//判断如果为死路

{

p[i][j]=1;

x=i;

y=j;

Push(x,y,S);

for(;;)

{

Pop(S);//弹出栈顶元素

x=Topx(S);

y=Topy(S);//返回栈顶元素横纵坐标

if( p[x-1][y]==0)

{

i=x-1;

j=y;

p[i][j]=1;

x=i;

y=j;

Push(x,y,S);

break;

}

else if(p[x-1][y]==1 && p[x][y+1]==0)

{

i=x;

j=y+1;

p[i][j]=1;

x=i;

y=j;

Push(x,y,S);

break;

}

else if(p[x-1][y]==1 && p[x][y+1]==1 && p[x+1][y]==0) {

i=x+1;

j=y;

p[i][j]=1;

x=i;

y=j;

Push(x,y,S);

break;

}

else if(p[x-1][y]==1 && p[x][y+1]==1 && p[x+1][y]==1 && p[x][y-1]==0)

{

i=x;

j=y-1;

p[i][j]=1;

x=i;

y=j;

Push(x,y,S);

break;

}//判断弹出后栈顶元素周围有无通路

else if(x==1 && y==1)

{

printf("There is no way out");

getchar();

return 0;

}//如果栈顶元素为入口则迷宫无出路

}

}

}while(i!=n1-2 || j!=n2-2);//循环截止条件}

printf("Success!\n The route is:\n");

for(i=0;;i++)

{

a=Topx(S);

b=Topy(S);

Pop(S);

x1[i]=a;

y1[i]=b;//将栈顶元素坐标存储在数组中

if(a==1 && b==1)

{

getchar();

break;

}

}

for(i=max-1;i>=0;)

{

if(x1[i]!=0 && (x1[i]!=x1[i-1] || y1[i]!=y1[i-1]))

{

printf("<%d ,%d> ",x1[i],y1[i]);

i--;

}

else if(x1[i]!=0 && (x1[i]==x1[i-1] && y1[i]==y1[i-1])) {

printf("<%d ,%d> ",x1[i],y1[i]);

i=i-2;

}

else

i--;

}//倒序打印数组得到顺序出路坐标

printf("<%d ,%d>",n1-2,n2-2);//打印出口坐标

getchar();

return 0;

}

void MakeNull(MAZE &S) //清空栈的函数

{

S = new node;

S->next = NULL;

}

void Push(Elementtype x,Elementtype y, MAZE S)//压栈函数{

MAZE stk;

stk = new node;

stk->val1 = x;

stk->val2 = y;

stk->next = S->next;

S->next = stk;

}

void Pop(MAZE S)//弹出函数

{

MAZE stk;

if(S->next)

{

stk = S->next;

S->next = stk->next;

delete stk;

}

}

Elementtype Topx(MAZE S)//返回横坐标函数

{

if(S->next)

return(S->next->val1);

else

return NULL;

}

Elementtype Topy(MAZE S)//返回纵坐标函数{

if(S->next)

return(S->next->val2);

else

return NULL;

}

五.程序运行结果

运行程序后,首先输入迷宫的长度和宽度

假设迷宫是8*8的(也可以为其他大小)。

输入后若没有出路,则显示“There is no way out”,程序结束。

输入后若迷宫有出路,则显示Success

再次按下回车键,则打印出迷宫路径

程序结束

六.程序运行结果自评

该程序运用栈的思想,成功解决了迷宫问题。下面对上述运行结果进行简要分析:

当迷宫没有出路时,系统首先走到2,2点弹出,发现2,1点下方为出路,然后继续向下走。但是走到5,1点时发现周围再次为死路,只能不停弹出,同时检测周围有无出路。

当弹出到1,1,点时,发现迷宫没有出路,程序结束。

当迷宫有出路时,系统按照既定规则移动,在3,5点时并未直接向下走向4,5点,而是按照判断顺序向右移动。当走到1,8点时发现为死路,则不停弹出并且检测周围有无出路。弹出到3,5时发现4,5可以走,则继续走下去,直到走到终点,程序结束。

在调试程序时,对栈顶元素进行观测,当程序分步执行时,可以清楚地看到栈里面元素的变化,从而分析出程序完成了的压栈、弹出的步骤。

在编写与调试程序的过程中,我遇到了很多问题。其中最主要的有动态数组的生成、对栈的概念的理解与栈的实现、具体算法的判断标准与循环结束条件等等。通过加设断点、分步执行程序、观测变量值等方法,不断对程序进行改进,直到最终成型。在这过程中,我对C语言的使用有了进一步的熟悉,对栈的思想有了更深入的了解。

相关主题
相关文档
最新文档