栈解决迷宫求解

/*   数据结构分析与学习专栏
*   Copyright (c) 2015, 山东大学 计算机科学与技术专业 学生
*   All rights reserved.
*   作    者:   高祥
*   完成日期:  2015 年 4 月 4 日
*   版 本 号:010

*任务:使用栈求解迷宫通路。

*算法思想:
do
{
    若当前位置可通,则
    {
       将当前位置插入栈顶;
       若该位置是出口位置,则结束;
       否则切换当前位置的右邻块(从右开始,顺时针方向)为新的当前位置;
    }
    否则,若栈不空
    {
        若栈顶位置的四周均不可通,则
        {
           删去栈顶元素;
           若栈不空,则重新测试新的栈顶位置,
           直到找到一个四周未全部测试完的栈顶位置或出栈至栈空;
         }
        若栈不空且栈顶位置尚有其他方向未经探索,
        则设定新的当前位置为顺时针方向旋转找到的栈顶位置的下一块相邻块;
    }
}
while(栈非空)

*主要函数:
*   1.void InitMaze(int maze[12][12],int mazesize);//初始化迷宫
*   2.void OutputMaze(int maze[12][12],int mazesize);//输出迷宫
*   3.void InitStack(SqStack &s);//初始化栈
*   4.void MazePath(SqStack &s, PosType start, PosType target);//寻找路径
*   5.int Pass(PosType pos);//判断当前位置能否通过
*   6.void Markfoot(PosType pos);//标记已经通过的通路
*   7.void Push(SqStack &s,SElemType &e);//压入元素
*   8.void Pop(SqStack &s,SElemType &e);//弹出元素
*   9.int IsEmpty(SqStack s);//判断栈是否为空
*   10.PosType NextPos(PosType now,int dir);//更新当前位置并返回
*   11.void OutputPath(SqStack s);//输出找到的路径

*运行示例:
请输入要创建的正方形迷宫的尺寸(1——10之间,输入0退出程序):8
请输入0(自动创建迷宫)或1(手动创建迷宫):0
创建的迷宫为(最外面的‘#’表示围墙):
# # # # # # # # # #
# 0 0 0 0 0 0 0 1 #
# 0 1 0 0 0 1 1 0 #
# 1 1 0 0 0 0 0 0 #
# 1 0 0 1 0 1 1 0 #
# 0 0 1 1 1 1 1 0 #
# 0 0 1 0 1 0 1 1 #
# 0 0 0 1 1 1 1 0 #
# 0 0 1 0 1 1 1 0 #
# # # # # # # # # #
请输入起点的行数和列数:
8 1
请输入终点的行数和列数:5 8
第1步:(8,1),向 右 走;
第2步:(8,2),向 上 走;
第3步:(7,2),向 左 走;
第4步:(7,1),向 上 走;
第5步:(6,1),向 右 走;
第6步:(6,2),向 上 走;
第7步:(5,2),向 左 走;
第8步:(4,2),向 右 走;
第9步:(4,3),向 上 走;
第10步:(3,3),向 右 走;
第11步:(3,4),向 右 走;
第12步:(3,5),向 右 走;
第13步:(3,6),向 右 走;
第14步:(3,7),向 右 走;
第15步:(3,8),向 下 走;
第16步:(4,8),向 下 走;
第17步:(5,8),到达目标位置。

注意:
利用当前这种算法不能保证找到的路径是最短的,只能保证可通。
*/
#include<iostream>
#include<cstdlib>
using namespace std;

#define MAXSIZE 100

typedef struct
{
    int row;//行数
    int line;//列数
} PosType;//位置坐标类型

typedef struct
{
    int order;//当前可行位置在路径上的序号(第几步)
    PosType seat;//当前可行位置的坐标
    int dir;//当前可行位置下一步前进的方向(1、2、3、4分别对应右、下、左、上)
} SElemType;//栈的元素类型

typedef struct
{
    SElemType * top;
    SElemType * base;
} SqStack;//栈类型

int maze[12][12];//迷宫数组

void InitMaze(int maze[12][12],int mazesize);//初始化迷宫
void OutputMaze(int maze[12][12],int mazesize);//输出迷宫
void InitStack(SqStack &s);//初始化栈
void MazePath(SqStack &s, PosType start, PosType target);//寻找路径
int Pass(PosType pos);//判断当前位置能否通过
void Markfoot(PosType pos);//标记已经通过的通路
void Push(SqStack &s,SElemType &e);//压入元素
void Pop(SqStack &s,SElemType &e);//弹出元素
int IsEmpty(SqStack s);//判断栈是否为空
PosType NextPos(PosType now,int dir);//更新当前位置并返回
void OutputPath(SqStack s);//输出找到的路径

int main()
{
    while(1)
    {
        cout<<"请输入要创建的正方形迷宫的尺寸(1——10之间,输入0退出程序):";
        int mazesize;
        cin>>mazesize;
        if(mazesize==0)
        {
            return 0;
        }
        if(mazesize<1||mazesize>10)
        {
            cout<<"请输入合适的尺寸大小!\n";
            continue;
        }

        InitMaze(maze,mazesize);//初始化迷宫
        cout<<"创建的迷宫为(最外面的‘#’表示围墙):\n";
        OutputMaze(maze,mazesize);

        PosType start,target;
        cout<<"请输入起点的行数和列数:";
        cin>>start.row>>start.line;
        cout<<"请输入终点的行数和列数:";
        cin>>target.row>>target.line;

        SqStack s;
        InitStack(s);//初始化栈
        MazePath(s,start,target);//寻找路径
    }
    return  0;
}

void InitMaze(int maze[12][12],int mazesize)//初始化迷宫
{
INPUT:
    cout<<"请输入0(自动创建迷宫)或1(手动创建迷宫):";
    int operate;
    cin>>operate;

    //要创建的迷宫四周添上一圈围墙,1表示墙,0表示通路
    for(int i=0; i<mazesize+2; i++)
    {
        maze[0][i]=1;
        maze[mazesize+1][i]=1;
    }

    if(operate==0)//自动创建
    {
        for( int i=1; i<mazesize+1; i++)
        {
            maze[i][0]=1;
            for(int j=1; j<mazesize+1; j++)
            {
                maze[i][j]=rand()%2;
            }
            maze[i][mazesize+1]=1;
        }
    }
    else if(operate==1)//手动输入
    {
        for( int i=1; i<mazesize+1; i++)
        {
            maze[i][0]=1;
            for(int j=1; j<mazesize+1; j++)
            {
                cin>>maze[i][j];
            }
            maze[i][mazesize+1]=1;
        }
    }
    else
    {
        cout<<"请输入正确的操作数字!\n";
        goto INPUT;
    }
}

void OutputMaze(int maze[12][12],int mazesize)//输出迷宫
{
    //围墙用‘#’表示
    for(int i=0; i<mazesize+2; i++)
    {
        cout<<"# ";
    }
    cout<<endl;

    for( int i=1; i<mazesize+1; i++)
    {
        cout<<"# ";
        for(int j=1; j<mazesize+1; j++)
        {
            cout<<maze[i][j]<<" ";
        }
        cout<<"#\n";
    }

    for(int i=0; i<mazesize+2; i++)
    {
        cout<<"# ";
    }
    cout<<endl;
}

void InitStack(SqStack &s)//初始化栈
{
    s.base=(SElemType *)malloc(MAXSIZE*sizeof(SElemType));//栈最多存取10*10=100个位置
    s.top=s.base;
}

void MazePath(SqStack &s, PosType start, PosType target)//寻找路径
{
    PosType curpos=start;//当前位置初始化为出发位置
    int curstep=1;//已经走的步数
    do
    {
        if (Pass(curpos))//当前位置可通过
        {
            Markfoot(curpos);//将通过的通路变为不能通过的,防止走回路

            SElemType e;//将要压入栈的元素
            e.dir =1;//首先都向右走
            e.order = curstep;
            e.seat= curpos;
            Push(s,e);//压入存放路径的栈

            if (curpos.row==target.row && curpos.line==target.line)//到达目标位置
            {
                OutputPath(s);//输出路径
                return;
            }

            curpos = NextPos(curpos, 1);//更新当前位置(当前位置的东邻)
            curstep++;//步数+1
        }
        else  if (!IsEmpty(s))//当前位置不能通过
        {
            SElemType &e=*(s.top-1);//栈顶位置

            while (e.dir==4 && !IsEmpty(s))//栈顶位置的4个方向全部尝试完毕均不能走且栈非空:弹出栈顶元素
            {
                Pop(s,e);
                curstep--;//步数-1
            }

            if (!IsEmpty(s)&&e.dir<4)//栈顶位置有还未尝试的方向
            {
                e.dir++;//换下一个方向
                curpos = NextPos(e.seat, e.dir);//当前位置更新为新方向的相邻块
            }
        }
    }
    while (!IsEmpty(s));

    cout<<"无法找到路径。\n";
}

int Pass(PosType pos)//判断当前位置能否通过
{
    if(maze[pos.row][pos.line]==0)
    {
        return 1;
    }
    return 0;
}

void Markfoot(PosType pos)//标记已经通过的通路
{
    maze[pos.row][pos.line]=1;
}

void Push(SqStack &s,SElemType &e)//压入元素
{
    *s.top=e;
    s.top++;
}

void Pop(SqStack &s,SElemType &e)//弹出元素
{
    if(!IsEmpty(s))
    {
        s.top--;
        e=*(s.top-1);
    }
}

int IsEmpty(SqStack s)//判断栈是否为空
{
    if(!s.base||s.base==s.top)
    {
        return 1;
    }
    return 0;
}

PosType NextPos(PosType now,int dir)//更新当前位置并返回
{
    PosType returnpos;
    switch(dir)
    {
    case 1:
        returnpos.row=now.row;
        returnpos.line=now.line+1;
        break;

    case 2:
        returnpos.row=now.row+1;
        returnpos.line=now.line;
        break;

    case 3:
        returnpos.row=now.row;
        returnpos.line=now.line-1;
        break;

    case 4:
        returnpos.row=now.row-1;
        returnpos.line=now.line;
        break;
    }
    return returnpos;
}

void OutputPath(SqStack s)//输出找到的路径
{
    while(s.base!=s.top-1)
    {
        cout<<"第"<<s.base->order<<"步:"<<"("<<s.base->seat.row<<","<<s.base->seat.line<<"),向 ";
        switch(s.base->dir)
        {
        case 1:
            cout<<"右";
            break;

        case 2:
            cout<<"下";
            break;

        case 3:
            cout<<"左";
            break;

        case 4:
            cout<<"上";
            break;
        }

        cout<<" 走;\n";
        s.base++;
    }
    cout<<"第"<<s.base->order<<"步:"<<"("<<s.base->seat.row<<","<<s.base->seat.line<<"),到达目标位置。\n";
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值