用c++写一个迷宫程序

用c++写一个迷宫程序,第1张

#include<iostream>

using namespace std;

class T //定义描述迷宫中当前位置的结构类型

{

public:

int x; //x代表当前位置的行坐标

int y; //y代表当前位置的列坐标

int dir; //0:无效,1:东,2:南,3:西,4:北

};

class LinkNode //链表结点

{

friend class Stack;

public:

T data;

LinkNode next;

};

class Stack

{

private:

LinkNode top; //指向第一个结点的栈顶指针

public:

Stack(); //构造函数,置空栈

~Stack(); //析构函数

void Push(T e); //把元素data压入栈中

T Pop(); //使栈顶元素出栈

T GetPop(); //取出栈顶元素

void Clear(); //把栈清空

bool empty(); //判断栈是否为空,如果为空则返回1,否则返回0

};

Stack::Stack() //构造函数,置空栈

{

top=NULL;

}

Stack::~Stack() //析构函数

{

}

void Stack::Push(T e) //把元素x压入栈中

{

LinkNode P;

P=new LinkNode;

P->data=e;

P->next=top;

top=P;

}

T Stack::Pop() //使栈顶元素出栈

{

T Temp;

LinkNode P;

P=top;

top=top->next;

Temp=P->data;

delete P;

return Temp;

}

T Stack::GetPop() //取出栈顶元素

{

return top->data;

}

void Stack::Clear() //把栈清空

{

top=NULL;

}

bool Stack::empty() //判断栈是否为空,如果为空则返回1,否则返回0

{

if(top==NULL) return 1;

else return 0;

}

int move[4][2]={{0,1},{1,0},{0,-1},{-1,0}}; //定义当前位置移动的4个方向

bool Mazepath(int maze,int m,int n);

//寻找迷宫maze中从(0,0)到(m,n)的路径

//到则返回true,否则返回false

void PrintPath(Stack p); //输出迷宫的路径

void Restore(int maze,int m,int n); //恢复迷宫

int GetMaze(int &m,int &n); //获取迷宫

//返回存取迷宫的二维指针

int main()

{

int m=0,n=0; //定义迷宫的长和宽

int maze; //定义二维指针存取迷宫

maze=GetMaze(m,n); //调用GetMaze(int &m,int &n)函数,得到迷宫

if(Mazepath(maze,m,n)) //调用Mazepath(int maze,int m,int n)函数获取路径

cout<<"迷宫路径探索成功!\n";

else cout<<"路径不存在!\n";

return 0;

}

int GetMaze(int &m,int &n)//返回存取迷宫的二维指针

{

int maze; //定义二维指针存取迷宫

int i=0,j=0;

cout<<"请输入迷宫的长和宽:";

int a,b;cin>>a>>b; //输入迷宫的长和宽

cout<<"请输入迷宫内容:\n";

m=a;

n=b; //m,n分别代表迷宫的行数和列数

maze=new int [m+2]; //申请长度等于行数加2的二级指针

for(i= 0;i<m+2;i++) //申请每个二维指针的空间

{

maze[i]=new int[n+2];

}

for(i=1;i<=m;i++) //输入迷宫的内容,0代表可通,1代表不通

for(j=1;j<=n;j++)

cin>>maze[i][j];

for(i=0;i<m+2;i++)

maze[i][0]=maze[i][n+1]=1;

for(i=0;i<n+2;i++)

maze[0][i]=maze[m+1][i]=1;

return maze; //返回存贮迷宫的二维指针maze

};

bool Mazepath(int maze,int m,int n)//寻找迷宫maze中从(0,0)到(m,n)的路径

//到则返回true,否则返回false

{

Stack q,p; //定义栈p、q,分别存探索迷宫的过程和存储路径

T Temp1,Temp2;

int x,y,loop;

Temp1x=1;

Temp1y=1;

qPush(Temp1); //将入口位置入栈

pPush(Temp1);

maze[1][1]=-1; //标志入口位置已到达过

while(!qempty()) //栈q非空,则反复探索

{

Temp2=qGetPop(); //获取栈顶元素

if(!(pGetPop()x==qGetPop()x&&pGetPop()y==qGetPop()y))

pPush(Temp2);

//如果有新位置入栈,则把上一个探索的位置存入栈p

for(loop=0;loop<4;loop++) //探索当前位置的4个相邻位置

{

x=Temp2x+move[loop][0]; //计算出新位置x位置值

y=Temp2y+move[loop][1]; //计算出新位置y位置值

if(maze[x][y]==0) //判断新位置是否可达

{

Temp1x=x;

Temp1y=y;

maze[x][y]=-1; //标志新位置已到达过

qPush(Temp1); //新位置入栈

}

if((x==(m))&&(y==(n))) //成功到达出口

{

Temp1x=m;

Temp1y=n;

Temp1dir=0;

pPush(Temp1); //把最后一个位置入栈

PrintPath(p); //输出路径

Restore(maze,m,n); //恢复路径

return 1; //表示成功找到路径

}

}

if(pGetPop()x==qGetPop()x&&pGetPop()y==qGetPop()y)

//如果没有新位置入栈,则返回到上一个位置

{

pPop();

qPop();

}

}

return 0; //表示查找失败,即迷宫无路经

}

void PrintPath(Stack p) //输出路径

{

cout<<"迷宫的路径为\n";

cout<<"括号内的内容分别表示为(行坐标,列坐标,数字化方向,方向)\n";

Stack t; //定义一个栈,按从入口到出口存取路径

int a,b;

T data;

LinkNode temp;

temp=new LinkNode; //申请空间

temp->data=pPop(); //取栈p的顶点元素,即第一个位置

tPush(temp->data); //第一个位置入栈t

delete temp; //释放空间

while(!pempty()) //栈p非空,则反复转移

{

temp=new LinkNode;

temp->data=pPop(); //获取下一个位置

//得到行走方向

a=tGetPop()x-temp->datax; //行坐标方向

b=tGetPop()y-temp->datay; //列坐标方向

if(a==1) temp->datadir=1; //方向向下,用1表示

else if(b==1) temp->datadir=2; //方向向右,用2表示

else if(a==-1) temp->datadir=3; //方向向上,用3表示

else if(b==-1) temp->datadir=4; //方向向左,用4表示

tPush(temp->data); //把新位置入栈

delete temp;

}

//输出路径,包括行坐标,列坐标,下一个位置方向

while(!tempty()) //栈非空,继续输出

{

data=tPop();

cout<<'('<<datax<<','<<datay<<','<<datadir<<","; //输出行坐标,列坐标

switch(datadir) //输出相应的方向

{

case 1:cout<<"↓)\n";break;

case 2:cout<<"→)\n";break;

case 3:cout<<"↑)\n";break;

case 4:cout<<"←)\n";break;

case 0:cout<<")\n";break;

}

}

}

void Restore(int maze,int m,int n) //恢复迷宫

{

int i,j;

for(i=0;i<m+2;i++) //遍历指针

for(j=0;j<n+2;j++)

{

if(maze[i][j]==-1) //恢复探索过位置,即把-1恢复为0

maze[i][j]=0;

}

}

示例输出:

测试1:

请输入迷宫的长和宽:5 5

请输入迷宫内容:

0 1 1 0 0

0 0 1 1 0

1 0 0 1 1

1 0 0 1 0

1 1 0 0 0

迷宫的路径为

括号内的内容分别表示为(行坐标,列坐标,数字化方向,方向)

(1,1,1,↓)

(2,1,2,→)

(2,2,1,↓)

(3,2,1,↓)

(4,2,2,→)

(4,3,1,↓)

(5,3,2,→)

(5,4,2,→)

(5,5,0,)

迷宫路径探索成功!

测试2:

请输入迷宫的长和宽:9 8

请输入迷宫内容:

0 0 1 0 0 0 1 0

0 0 1 0 0 0 1 0

0 0 0 0 1 1 0 1

0 1 1 1 0 0 1 0

0 0 0 1 0 0 0 0

0 1 0 0 0 1 0 1

0 1 1 1 1 0 0 1

1 1 0 0 0 1 0 1

1 1 0 0 0 0 0 0

迷宫的路径为

括号内的内容分别表示为(行坐标,列坐标,数字化方向,方向)

(1,1,1,↓)

(2,1,1,↓)

(3,1,1,↓)

(4,1,1,↓)

(5,1,2,→)

(5,2,2,→)

(5,3,1,↓)

(6,3,2,→)

(6,4,2,→)

(6,5,3,↑)

(5,5,2,→)

(5,6,2,→)

(5,7,1,↓)

(6,7,1,↓)

(7,7,1,↓)

(8,7,1,↓)

(9,7,2,→)

(9,8,0,)

迷宫路径探索成功!

该算法是不稳定的,其时空复杂度不仅和m,n有关,还和mg[][]的具体数值有关。

最坏情况下:每个点都试探过才走到终点。此时时间复杂度为:(mn-1)4,(其中4为4个方向),空间复杂度mn2,(其中mn为存储迷宫图空间,mn为栈空间);

再好情况下:一次试探过就走到终点。此时时间复杂度为:(min(m,n)-1),空间复杂度mn;

所以:

该算法时间复杂度为:[(mn-1)4+(min(m,n)-1)]/2,约为2×m×n

空间复杂度为3mn/2

本程序的前提是将迷宫保存在一个二维数组里,可走的地方为0,不可走的地方为1。由于采用回朔算法,不使用递归,所以首先应该建立一个栈来保存路径,路径是用一个一个点来表示的,也就是说栈中保存的是一系列点的列表。

栈节点类型说明:

struct StackNode

{

POINT Point;

struct StackNode Next, Prev;//双向链表形式

};

栈结构用一个类(CPointStack)实现,声明如下:

class CPointStack

{

public:

void ClearStack();//清空栈

void InitStack();//初始化栈

bool Pop(POINT &pt);//d出顶端元素,并给出该点的坐标,返回是否d出成功

bool Push(POINT pt);//将pt点的信息压入栈,返回是否压入成功

CPointStack();

virtual ~CPointStack();

protected:

StackNode m_psnTop;//栈顶指针

StackNode m_snBottom;//栈底,不保存点信息

};

以下为成员函数实现,都是一些数据结构的 *** 作,应该没什么好说的:

//构造时初始化栈

CPointStack::CPointStack()

{

InitStack();

}

//析构时清空栈

CPointStack::~CPointStack()

{

ClearStack();

}

//将点压入栈(成功返回true,失败返回false)

bool CPointStack::Push(POINT pt)

{

StackNode NewNode = new StackNode;

//是否返回true主要看这里申请内存是否成功

if(!NewNode)

return false;

NewNode->Point = pt;

NewNode->Prev = m_psnTop;

NewNode->Next = NULL;

m_psnTop->Next = NewNode;

m_psnTop = NewNode;

return true;

}

//将点d出栈(成功返回true,栈为空则返回false)

bool CPointStack::Pop(POINT &pt)

{

if(m_psnTop == &m_snBottom)//是否返回true主要看这里栈是否为空

return false;

StackNode p;

p = m_psnTop;

m_psnTop = m_psnTop->Prev;

pt = p->Point;

delete p;

m_psnTop->Next = NULL;

return true;

}

//初始化栈

void CPointStack::InitStack()

{

m_psnTop = &m_snBottom;

m_snBottomNext = NULL;

m_snBottomPrev = NULL;

}

//清空栈

void CPointStack::ClearStack()

{

StackNode p;

while(m_psnTop != &m_snBottom)

{

p = m_psnTop;

m_psnTop = m_psnTop->Prev;

delete p;

}

}

接下来设计怎样走出这个迷宫,也就是迷宫算法的主体部分。再次用一个类实现。

在设计这个类时,我考虑到以下几点:

1、迷宫入口和出口的坐标

2、保存迷宫的2维数组

3、获得路径的函数

但是实际设计时由于没有考虑太多问题,只是以设计迷宫算法和解决一个具体迷宫为目的,所以没有考虑动态大小的迷宫,而是将迷宫大小定为601×401。而且在设计迷宫算法后没有将路径顺序输出而是直接在原图中标识(在保存迷宫数据的表中设置经过的点为2而将死路点设置为3)。

这样迷宫类(CGoMaze)的声明为:

class CGoMaze

{

public:

void Go();//寻找路径的函数

POINT m_ptIn;//入口坐标

POINT m_ptOut;//出口坐标

BYTE m_btArrMaze[401][601];//保存迷宫的二维表

CGoMaze();

virtual ~CGoMaze();

};

最后让我们来看一下CGoMaze::Go()这个函数:

我们模仿人走迷宫时的思路,设置一个当前点,一个目标点(下一个要走的点)。初始情况下当前点为入口,终止条件为当前点为出口,这样,我们的函数大概结构就出来了。

在从入口到出口的过程中程序对当前点的上、下、左、右四个点依次进行判断,当发现任一个方向是未走过的区域时,就将当前点指向那个点进行尝试,同时将当前点入栈并做标记。而当4个方向都不通或已走过时,则为死路,标记当前点为死路并从栈中d出上一个点继续进行尝试,这时因为当前点已被标记为死路,则d出上一个点时就不会重复这条路,达到寻找正确路径的效果。

Go函数的具体实现如下,其实挺简单的^_^:

void CGoMaze::Go()

{

CPointStack psPath;//保存路径的栈

POINT ptCur = m_ptIn, ptNext;//设置当前点为入口

while(ptCurx != m_ptOutx || ptCury != m_ptOuty)//判断是否已经走出

{

ptNext = ptCur;//设置目标点为当前点,便于下面偏移

if(m_btArrMaze[ptCury - 1][ptCurx] == 0)

ptNexty --;//如果上方是空的,则目标点向上偏移

else if(m_btArrMaze[ptCury][ptCurx - 1] == 0)

ptNextx --;//如果左边是空的,则目标点向左偏移

else if(m_btArrMaze[ptCury + 1][ptCurx] == 0)

ptNexty ++;//如果下方是空的,则目标点向下偏移

else if(m_btArrMaze[ptCury][ptCurx + 1] == 0)

ptNextx ++;//如果右边是空的,则目标点向右偏移

else

{//这里是没有路的状态

m_btArrMaze[ptCury][ptCurx] = 3;//标记为死路

psPathPop(ptCur);//d出上一次的点

continue;//继续循环

}

//如果有路的话会执行到这里

m_btArrMaze[ptCury][ptCurx] = 2;//标记当前点为路径上的点

psPathPush(ptCur);//当前点压入栈中

ptCur = ptNext;//移动当前点

}

}

其实这个部分可以将栈设置为CGoMaze类的成员,然后在Go函数里加上:

psPathClearStack();

这样就可以用Timer来演示走迷宫的过程了

/ 迷宫矩阵

1 1 1 1 1 1 1 1 1 1

1 0 0 0 0 1 0 0 0 1

1 1 1 0 0 1 0 1 0 1

1 0 0 0 1 0 0 0 0 1

1 0 0 0 0 1 0 1 0 1

1 1 0 1 0 0 0 0 0 1

1 0 0 1 1 1 0 1 1 1

1 1 0 0 0 1 0 0 0 1

1 1 1 1 1 1 1 1 1 1

/

#include<stdioh>

#define m 7

#define n 8

void path()

{

int maze[m+2][n+2] ;

int move[4][2]={ {0,-1},{-1,0},{0,1},{1,0} };

int s[54][3];

int top=0;

int i,j,k,f=0;

int g,h,p;

for(i=0;i<m+2;++i)

for(j=0;j<n+2;++j)

scanf("%d",&maze[i][j]);

maze[1][1]=2;

s[top][0]=1;

s[top][1]=1;

s[top][2]=0;

++top;

while(top!=0&&f==0)

{

--top;

i=s[top][0];

j=s[top][1];

k=s[top][2];

while(k<4)

{

g=i+move[k][0];

h=j+move[k][1];

if(g==m&&h==n&&maze[g][h]==0)

{

for(p=0;p<top;++p)

printf("%3d,%d\n",s[p][0],s[p][1]);

printf("%3d,%d\n",i,j);

printf("%3d,%d\n",m,n);

f=1;

}//if

if(maze[g][h]==0)

{

maze[g][h]=2;

s[top][0]=i;

s[top][1]=j;

s[top][2]=k;

++top;

i=g;

j=h;

k=0;

}//if

k=k+1;

}//while

}//while

if(f==0)

printf("no path\n");

}//pathvoid main()

{

path();

}

这个迷宫的路径不是唯一的,因此从不同方向开始试探执行结果也可能会不唯一。我写的是参考书上的,共有八个方向可以试探。

栈解决迷宫主要的几个问题:

1迷宫的存储

2栈的设计

3试探方向

4不重复到达某点,即不陷入死循环

如果对算法有什么疑问,或是我的回答有错误的地方,可以Hi我。

#define LINES 9 // 定义行数

#define COLS 8 // 定义列数

#include <stdioh>

#include <stdlibh>

#include <malloch>

typedef struct{

int line;

int col;

}MOVE; // 定义试探方向的结构体

MOVE to[8] = {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}}; // 定义数组,存放8个试探方向

typedef struct{ // 行、列、方向构成的三元组

int x;

int y;

int d;

}DataType;

typedef struct node{

DataType element;

struct node next;

}StackNode,LinkStack;

LinkStack InitStack(LinkStack s); // 栈初始化

LinkStack PushStack(LinkStack,DataType ); // 入栈函数

LinkStack PopStack(LinkStack,DataType ); // 出栈函数

int EmptyStack(LinkStack s); // 判定栈空

int path(int maze[][COLS+2]); // 打印路径

void printpath(LinkStack s,DataType t);

int main( void )

{

int i,j;

int maze[LINES+2][COLS+2] = // 定义存放迷宫的数组并初始化

{1,1,1,1,1,1,1,1,1,1,

1,0,0,1,0,0,0,1,0,1,

1,0,0,1,0,0,0,1,0,1,

1,0,0,0,0,1,1,0,1,1,

1,0,1,1,1,0,0,1,0,1,

1,0,0,0,1,0,0,0,0,1,

1,0,1,0,0,0,1,0,1,1,

1,0,1,1,1,1,0,0,1,1,

1,1,1,0,0,0,1,0,1,1,

1,1,1,0,0,0,0,0,0,1,

1,1,1,1,1,1,1,1,1,1

};

for(i=1;i<LINES+1;i++)

{

for(j=1;j<COLS+1;j++){

if( 0 == maze[i][j] ){

printf("□");

}

else{

printf("■");

}

}

printf("\n");

}

if( path(maze) ){

printf("找到一条路径\n");

for(i=1;i<LINES+1;i++)

{

for(j=1;j<COLS+1;j++)

{

if( 0 == maze[i][j] ){

printf("□");

}

else if( 1 == maze[i][j]){

printf("■");

}

else{

printf("☆");

}

}

printf("\n");

}

}

else{

printf("迷宫无路径\n");

}

return 0;

}

LinkStack InitStack(LinkStack s)

{

return NULL;

}

LinkStack PushStack(LinkStack s,DataType t)

{

StackNode p;

p = NULL;

p = (StackNode )malloc(sizeof(StackNode));

if(!p){

printf("申请结点失败\n");

exit(1);

}

p->element = t;

p->next = s;

s = p;

return s;

}

LinkStack PopStack(LinkStack s,DataType t)

{

StackNode p = NULL;

if( EmptyStack(s) ){

printf("栈空\n");

return NULL;

}

p = s;

t = p->element;

s = s->next;

free(p);

p = NULL;

return s;

}

int EmptyStack(LinkStack s)

{

if( NULL == s ){

return 1;

}

return 0;

}

int path(int maze[][COLS+2])

{

int i,j,x1,y1,v;

DataType temp;

LinkStack top;

tempx = 1;

tempy = 1;

tempd = -1;

top = InitStack(top);

top = PushStack(top,&temp);

while( !EmptyStack(top) )

{

top = PopStack(top,&temp);

// 入口为(1,1),从0方向开始试探

x1 = tempx;

y1 = tempy;

v = tempd + 1;

while( v < 8 )

{

i = x1 + to[v]line;

j = y1 + to[v]col;

if( 0 == maze[i][j] ){ // 到达新点

tempx = x1;

tempy = y1;

tempd = v;

top = PushStack(top,&temp); // 坐标及方向入栈

x1 = i;

y1 = j;

maze[x1][y1] = -1; // 对已经到过的点做标记

if( x1 == LINES && y1 == COLS ){ // 到达出口

printpath(top,&temp); // 打印路径

return 1;

}

else{

v = 0;

}

}

else{

v++;

}

}

}

return 0;

}

void printpath(LinkStack s,DataType t)

{

while( !EmptyStack(s) )

{

printf("(%d, %d, %d)\n",s->elementx,s->elementy,s->elementd);

s = PopStack(s,t);

}

}

你这个题意表述得不是很完整。首先,这个迷宫的出口和入口坐标分别是哪个?也就是迷宫的起点和终点在哪?第二,行走的规则是什么?是只能横竖走?还是也可以斜着走。

然后像这类的寻路有一种很好的算法叫A寻路算法,你可以自己百度一下。大致的思路是从起点开始,维护两个表。第一个表是下一步可以到达的格子属性表,这个表中每个格子至少要有权值(也就是预计离目标远近的值)和父节点2个属性,而且必须按权值顺序排序。另外一个表是已经寻过路的格子。讲起来有点复杂,但做起来不是太难。百度一下吧。

以上就是关于用c++写一个迷宫程序全部的内容,包括:用c++写一个迷宫程序、C语言迷宫问题,求该算法的时间和空间的复杂度。迷宫的路径已经定义好,求出路的算法。、C++设计一个迷宫并走出来等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/sjk/10199180.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存