C/C++利用栈实现简单迷宫问题

//预编译区::  
#include "stdafx.h"  
#include<iostream>  
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#define MAXLEN 20       //迷宫包括外墙的最大行列数  
#define STACK_INIT_SIZE 100  
#define STACKINCREMENT 15  
#define TRUE 1  
#define FALSE 0  
#define OK 1  
#define ERROR 0  
#define OVERFLOW -2  
#define UNDERFLOW -3  
using namespace std;  
  
//数据结构定义区::  
typedef int status;  
  
//坐标位置类型  
typedef struct {  
    int r;      //迷宫中第r行  
    int c;      //迷宫中第c列  
}PosType;  
  
//栈中元素值域的类型  
typedef struct {  
    int ord;        //通道块在路径上的序号  
    PosType seat;       //通道块在迷宫上的通道位置  
    int di;     //从此通道块走向下一通道的方向  
}SElemType;  
  
//定义链式栈的存储结构  
struct LNode {  
    SElemType data;     //数据域  
    LNode *next;        //指针域  
};  
  
typedef struct LStack {  
    LNode *top;     //栈顶指针  
    LNode *base;        //栈底指针  
    int stacksize;      //栈的大小  
}SqStack;  
  
//迷宫类型(需要打印呈现)  
typedef struct {  
    int r;  
    int c;  
    char addr[MAXLEN][MAXLEN];      //表示通道的矩阵  
}MazeType;  
  
//函数声明区::  
void InitStack(LStack &s);  
status StackEmpty(LStack s);  
void PushStack(LStack &s, SElemType e);  
void Pop(LStack &s, SElemType &e);  
status DestroyStack(LStack &s);  
void OverturnStack(SqStack S, SqStack &T);  
void InitMaze(MazeType &maze);  
status CreatMaze(MazeType &maze, PosType &start, PosType &end);  
status WhetherPass(MazeType &maze, PosType curpos);  
void FootPrint(MazeType &maze, PosType curpos);  
PosType NextPos(PosType &curpos, int i);  
void MarkPrint(MazeType &maze, PosType curpos);  
status MazePath(MazeType &maze, PosType start, PosType end, SqStack &S);  
void PrintMaze(MazeType &maze, PosType start, PosType end);  
void PrintStack(SqStack S);  
  
//主函数  
int main(void) {  
    SqStack S, T;  
    InitStack(S); InitStack(T);  
    MazeType maze;  
    PosType start, end;  
    InitMaze(maze);  
    start.c = start.r = 0; end.c = end.r = 0;  
    printf("----------------创建迷宫开始----------------\n");  
    if (!CreatMaze(maze, start, end)) {  
        printf("初始化失败!!!\n");  
        exit(OVERFLOW);  
    }  
    printf("----------------创建迷宫结束----------------\n");  
    printf("\n");  
    printf("----------------原始迷宫模型图----------------\n");  
    PrintMaze(maze, start, end);  
    printf("\n");  
    printf("----------------走出迷宫的路径----------------\n");  
    if (!MazePath(maze, start, end, S))     //当栈被销毁的时候,则没有一条通路  
        printf("没有一条通路!!!\n");      //否则打印输出栈中的元素  
    else {  
        OverturnStack(S, T); PrintStack(T); DestroyStack(S);  
    }  
    printf("----------------迷宫路径模型图(o代表一条通路)----------------\n");  
    PrintMaze(maze, start, end);  
    system("pause");  
    return 0;  
}  
  
//---------栈的算法开始------------  
//构造一个空栈  
void InitStack(LStack &s) {  
    s.base = (LNode*)malloc(STACK_INIT_SIZE*sizeof(LNode));     //为指针p分配空间  
    if (!s.base) {  
        printf("分配失败,退出程序!");  
        exit(OVERFLOW);  
    }  
    s.top=s.base;       //将栈底和栈顶指针指向p指向的位置        
    s.base->next = NULL;     //栈顶指针的指针域置空  
    s.stacksize = STACK_INIT_SIZE;  
    return;  
}  
  
//若栈s为空栈,则返回true,否则返回false  
status StackEmpty(LStack s) {  
    if (s.top == s.base) return TRUE;       //若栈顶指针与栈底指针重合,则是空栈  
    else return FALSE;  
}  
  
//插入元素e成为新的栈顶元素  
void PushStack(LStack &s, SElemType e) {  
    if (s.top - s.base >= s.stacksize) {  
        s.base = (LNode*)realloc(s.base,(s.stacksize+STACKINCREMENT)*sizeof(LNode));  
        if (!s.base) exit(OVERFLOW);  
        s.top = s.base + s.stacksize;  
        s.stacksize += STACKINCREMENT;  
    }  
    (*s.top).data= e;  
    s.top++;  
    return;  
}  
  
//删除s的栈顶元素,并用e返回其值  
void Pop(LStack &s, SElemType &e) {  
    if (s.top == s.base) exit(ERROR);       //如果为空栈,退出  
    s.top--;  
    e = (*s.top).data;  
    return;  
}  
  
//栈s的销毁  
status DestroyStack(LStack &s) {  
    free(s.base);  
    s.base= NULL;  
    s.top=NULL;  
    s.stacksize = 0;  
    return OK;  
}  
  
//将栈S中的所有元素翻转致栈T:用于对于路径的输出,由于栈不能直接访问栈底指针,所以需要翻转  
void OverturnStack(SqStack S,SqStack &T){  
    SElemType e;  
    do{  
        Pop(S, e); PushStack(T, e);  
    } while (S.base != S.top);  
    return;  
}  
//---------栈的算法结束------------  
  
//---------迷宫实现开始------------  
//初始化迷宫  
void InitMaze(MazeType &maze){  
    maze.c = 0;  
    maze.r = 0;  
    return;  
}  
  
//创建迷宫  
status CreatMaze(MazeType &maze, PosType &start,PosType &end) {  
    int i, j, m=0, n=0;  
    printf("请输入迷宫的行数和列数(包含外墙):");  
    scanf_s("%d,%d", &maze.r, &maze.c);  
    for (i = 0; i < maze.c; i++) {  
        maze.addr[0][i] = '#';      //给出上下围墙  
        maze.addr[maze.r -1][i] = '#';  
    }  
    for (i = 1; i < maze.r-1; i++) {  
        maze.addr[i][0] = '#';      //给出左右围墙  
        maze.addr[i][maze.c - 1] = '#';  
    }  
    for (i = 1; i < maze.r-1; i++) {  
        for (j = 1; j < maze.c-1; j++) {  
            maze.addr[i][j] = ' ';      //将围墙内的通道块赋空值  
        }  
    }  
    printf_s("\n请输入迷宫入口:");  
    do {  
        scanf_s("%d,%d", &start.r, &start.c);  
        if (start.r == 0 || start.r >= maze.r || start.c >= maze.c) {     //超出迷宫界限的时候跳出本次循环,继续循环输入入口  
            printf("上一入口超出迷宫界限,请重新输入入口坐标!\n");      //入口不能设置在四角和上下两个边界上  
            continue;  
        }  
        else break;  
    } while (start.r == 0 || start.r >= maze.r || start.c >= maze.c);  
    printf("\n");  
    printf_s("请输入迷宫出口:");  
    do {  
        scanf_s("%d,%d", &end.r, &end.c);  
        if (end.r == 0 || end.c == 0 || end.r >= maze.r || end.c >= maze.c) {     //超出迷宫界限的时候跳出本次循环,继续循环输入入口  
            printf_s("上一出口超出迷宫界限,请重新输入出口坐标!\n");  
            continue;  
        }  
        else break;  
    } while (end.r == 0 || end.c == 0 || end.r >= maze.r || end.c >= maze.c);  
    maze.addr[start.r][start.c] = ' ';  
    maze.addr[end.r][end.c] = ' ';  
    printf("\n请输入障碍物的坐标(x,y)(以x,y=-1结束):\n");  
    while (m != -1) {  
        scanf_s("%d,%d", &m, &n);       //系统坐标原点默认为(0,0)  
        if (m == 0 || n== 0 || m >= maze.r || n > maze.c) {  
            printf("上一坐标输入错误,系统自动舍弃,请重新输入坐标!\n");   
            m = 0; n = 0; continue;  
        }  
        else if (m == -1 && n == -1) continue;  
        else maze.addr[m][n] = '#';  
    }  
    return OK;  
}  
  
//判断当前位置可否通过,可通过返回true  
status WhetherPass(MazeType &maze, PosType curpos) {  
    if (maze.addr[curpos.r][curpos.c] == ' ') return TRUE;  
    else return FALSE;  
}  
  
//若该通道块走过并且可通,就记录下来  
void FootPrint(MazeType &maze, PosType curpos) {  
    maze.addr[curpos.r][curpos.c] = 'o';  
    return;  
}  
  
//指示并返回下一位置的坐标  
PosType NextPos(PosType &curpos, int i) {  
    switch (i) {        //向各个方向前进一个单位,并返回位置值  
    case 1:curpos.c += 1; break;        //向东前进一个单位  
    case 2:curpos.r += 1; break;        //向南前进一个单位  
    case 3:curpos.c -= 1; break;        //向西前进一个单位  
    case 4:curpos.r -= 1; break;        //向北前进一个单位  
    default:exit(ERROR);  
    }  
    return curpos;  
}  
  
//曾经走过,但不是通路,就标记  
void MarkPrint(MazeType &maze, PosType curpos) {  
    maze.addr[curpos.r][curpos.c] = '@';  
    return;  
}  
  
//若迷宫存在一条通路,则求出一条通路存放到栈中  
status MazePath(MazeType &maze, PosType start, PosType end ,SqStack &S){  
    PosType curpos;     //记录当前元素位置  
    int curstep = 1,flag=0; //记录能通行的通道块在栈中的路径顺序  
    SElemType e;        //记录可压住栈中的当前通道块的信息  
    curpos = start;  
    printf("用抽象数据类型三元组【(x,y)方向】表示迷宫路径:\n");  
    do {  
        if (WhetherPass(maze, curpos)) {        //如果该路径块可通行  
            FootPrint(maze, curpos);        //记录下通行过的痕迹  
            e.ord = curstep;        //将栈中的顺序给e的ord属性  
            e.seat = curpos;        //将该通道块的位置给e的curpos属性  
            e.di = 1;       //将初始方向设为向东(1)  
            PushStack(S, e);        //将该可通的通道块压入栈  
            if (curpos.r == end.r&&curpos.c == end.c) {     //如果遇到了出口则退出  
                return TRUE;  
            }  
            else {      //如果没有遇到出口  
                curpos = NextPos(curpos, 1);        //那么寻找下一个位置  
                curstep++;      //计数器加1  
            }  
        }  
        else {      //如果该路径块不通  
            if (!StackEmpty(S)) {       //如果栈不为空  
                Pop(S, e);      //将栈顶元素出栈也就是退回上一个元素,将e返回出来判断是否再次进行方向的改变,也就是将栈顶元素进行悬挂操作  
                while (e.di == 4 && !StackEmpty(S)) {       //当四个方向都不通并且栈b不为空时  
                    MarkPrint(maze, e.seat);        //记录该通道块不通  
                    Pop(S, e);  
                    //将栈顶元素出栈也就是退回上一个位置  
                }  
                if (e.di < 4) {      //当四个方向没有尝试完时  
                    e.di++;     //换一个方向  
                    PushStack(S, e);        //将换方向之后的位置压栈  
                    curpos = NextPos(e.seat, e.di);     //当前位置下移  
                }  
            }  
        }  
    } while (!StackEmpty(S));  
    return FALSE;  
}  
  
//将标记路径信息输出到终端显示屏  
void PrintMaze(MazeType &maze,PosType start, PosType end) {  
    int i, j;  
    printf("          ");       //10个空格  
    for (i = 0; i <maze.c ; i++) printf("%2d", i);  
    printf("\n");  
    for (i = 0; i < maze.r; i++) {  
        if (i == start.r-1) printf("entrance%2d", start.r - 1);  
        else if (i == start.r)  printf("      ->%2d", start.r);  
        else printf("%10d", i);  
        for (j = 0; j < maze.c; j++) {  
            printf("%2c", maze.addr[i][j]);  
            if (i == end.r - 1 && j == end.c) printf(" exit");  
            else if (i == end.r&&j == end.c) printf("<-");  
        }  
        printf("\n");  
    }  
    return;  
}  
  
//输出栈中的路径  
void PrintStack(SqStack S){  
    int flag=0;  
    printf("迷宫中的一条通路如下:\n");  
    do{  
        S.top--;        //将栈顶指针指向想要输出的栈顶元素  
        if ( flag % 5 == 0) printf("\n");  
        switch (S.top->data.di) {  
        case 1:  
            printf("(%d,%d)向东->",S.top->data.seat.r, S.top->data.seat.c);  
            flag++; break;  
        case 2:  
            printf("(%d,%d)向南->", S.top->data.seat.r, S.top->data.seat.c);  
            flag++; break;  
        case 3:  
            printf("(%d,%d)向西->", S.top->data.seat.r, S.top->data.seat.c);  
            flag++; break;  
        case 4:  
            printf("(%d,%d)向北->", S.top->data.seat.r, S.top->data.seat.c);  
            flag++; break;  
        }  
    } while (S.base != S.top);  
    printf("结束\n");  
    return;  
}  

 

  • 8
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值