码迷,mamicode.com
首页 > 其他好文 > 详细

栈的运用---迷宫

时间:2014-11-04 22:28:59      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   io   color   ar   os   for   sp   

实验2-1 栈与迷宫求解
【实验目的】
1.熟悉C语言的上机环境VC6,掌握C语言程序设计方法与特点。
2.掌握栈的顺序存储结构的定义及C语言实现。
3.掌握栈的顺序存储结构上的各种基本操作。
4.应用栈实现迷宫通路算法。
5.迷宫求解的关键结构定义及C语言实现。
【问题说明】
一个迷宫可用n阶方阵表示,1表示能通过,0 表示不能通过。现假设老鼠从左上角[1,1]进入迷宫,编写算法,寻求一条从右下角[n,n] 出去的路径。下图是一个迷宫的示意图: 
迷宫示意图
【算法基本思想】
迷宫求解是栈的一个典型应用。基本算法思想是:
(1)若当前位置“可通”,则纳入“当前路径”,并继续朝着“下一位置”探索,即切换“下一位置”为“当前位置”,如此重复直至到达出口;
(2)若当前位置“不可通过”,则应顺着“来向”退回到“前一通道块”,然后朝着除“来向”之外的其他方向继续探索;
(3)若该通道块的四周4个方块均“不可通过”,则应从“当前路径”上删除该通道块。
注:
(1)下一位置:“当前位置”四周4个方向(东南西北)上相邻的方块。
(2)假设用栈记录当前路径,则栈顶存放的是“当前路径上最后一个通道块”。
(3)纳入路径:当前位置入栈。
(4)从当前路径上删除前一通道块:出栈。
 求迷宫中一条从入口到出口的路径的算法,具体请参见p51。
【实验内容】
1.    顺序栈的初始化、元素的入栈、出栈、以及栈的判空。
2.    迷宫关键操作:
a)    迷宫的初始化
b)    判断当前位置可否通过
c)    为能通过的地方留下足迹,为当前走过的有效的步骤数
d)    探索下一位置并返回下一位置的坐标
e)    曾走过但不通的地方也留下足迹,为-1
f)    关键算法:迷宫存在从入口到出口的通道,则求得一条存放在栈中,并返回ture
g)    输出迷宫
3. 测试:
不同入口和出口的迷宫问题求解路径。
【实验重点】
1、    C语言定义顺序栈
2、    会多文件组织方式编写程序
3、    顺序栈的初始化、元素的入栈、出栈、以及栈的判空操作
4、    迷宫的关键算法。
【实验步骤与代码指导】
1.    定义相关结构:
(1)定义位置类型
typedef struct{
    int r;              //迷宫矩阵的行
    int c;              //迷宫矩阵的列
}PosType;

(2)定义栈的元素类型
typedef struct{  
    int ord;             //通道块在路径上的“序号”
    PosType seat;        //通道块在迷宫中的“坐标位置”
    int di;              //从此通道块走向下一通道块的“方向”,1-4表示东南西北    
}SElemType;         

(3)定义顺序/栈类型
typedef struct{
    SElemType *base;     //栈底指针,栈构造前和销毁后,base为NULL
    SElemType *top;      //栈顶指针
    int stacksize;       //当前已分配的存储空间,以元素为单位
}SqStack;                

(4)定义迷宫类型
typedef int MazeType[MAXLEN][MAXLEN]; //MAXLEN*MAXLEN二维数组 

2.建立头文件maze.h如下:
#ifndef _MAZE_H
#define  _MAZE_H

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "common.h"

#define STACK_INIT_SIZE 100   //存储空间初始化分配量
#define STACK_INCREMENT 10    //存储空间分配增量
#define MAXLEN 10

typedef struct{
    int r;              //迷宫矩阵的行
    int c;              //迷宫矩阵的列
}PosType;

typedef struct{  
    int ord;             //通道块在路径上的“序号”
    PosType seat;        //通道块在迷宫中的“坐标位置”
    int di;              //从此通道块走向下一通道块的“方向”,1-4表示东南西北    
}SElemType;              //栈的元素类型

typedef struct{
    SElemType *base;     //栈底指针,栈构造前和销毁后,base为NULL
    SElemType *top;      //栈顶指针
    int stacksize;       //当前已分配的存储空间,以元素为单位
}SqStack;                //栈类型-顺序存储

typedef int MazeType[MAXLEN][MAXLEN]; //MAXLEN*MAXLEN二维数组 //迷宫类型

Status InitStack(SqStack &S);        //初始化栈
Status DestroyStack(SqStack &S);     //销毁栈
Status Push(SqStack &S,SElemType e);  //向栈顶插入元素
Status Pop(SqStack &S,SElemType &e);  //出栈
Status StackEmpty(SqStack S);       //栈是否为空

Status InitMaze(MazeType &maze);                         //初始化迷宫
Status Pass(MazeType &maze,PosType curpos);               //判断当前位置可否通过
Status FootPrint(MazeType &maze,PosType curpos,int curstep);  //留下足迹,足迹为步骤数
PosType NextPos(PosType curpos,int i);             //探索下一位置并返回下一位置的坐标
Status MarkPrint(MazeType &maze,PosType curpos);            //曾走过但不通留下标记-1
//迷宫maze存在从入口start到end的通道则求得一条存放在栈中
Status MazePath(MazeType &maze,PosType start,PosType end);    
void PrintMaze(MazeType &maze);                               //输出迷宫
#endif

3. 再建立一个头文件common.h如下:
#ifndef _COMMON_H
#define  _COMMON_H
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
#endif

4. 将实现放在Maze.cpp里,文件内容如下:
#include <time.h>
#include "maze.h"

Status InitStack(SqStack &S){
    S.base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
    if(!S.base) exit(OVERFLOW);
    S.top=S.base;
    S.stacksize=STACK_INIT_SIZE;
    return OK;
}

Status DestroyStack(SqStack &S){
    if (S.base!=NULL){
        free(S.base);
        S.stacksize=0;
        printf("顺序栈已经销毁\n");
        return OK;
    }
    else return FALSE;
}

Status Push(SqStack &S,SElemType e){
    if (S.top-S.base>=S.stacksize ){
        S.base=(SElemType *) realloc(S.base,(S.stacksize+STACK_INCREMENT)*sizeof(SElemType));
        if(!S.base) exit(OVERFLOW);
        S.top=S.base+S.stacksize;
        S.stacksize+=STACK_INCREMENT;
    }
    *S.top++=e;
    return OK;
}

Status Pop(SqStack &S,SElemType &e){
    if(S.top==S.base) return ERROR;
    e=*--S.top;
    return OK;             
}

Status StackEmpty(SqStack S){
    if (S.base==S.top) return TRUE;
    else return FALSE;
}

//定义墙值为0,可通过路径为1,不可通过路径为-1
Status InitMaze(MazeType &maze){ 
    int i,j;            
    for(i=0;i<MAXLEN;i++){                     //迷宫行外墙
        maze[0][i]=0;
        maze[MAXLEN-1][i]=0;
    }
    for(i=0;i<MAXLEN;i++){                     //迷宫列外墙
        maze[i][0]=0;
        maze[i][MAXLEN-1]=0;
    }
    
    srand((unsigned)time(NULL));  //随机种子
    for(i=1;i<MAXLEN-1;i++)
        for(j=1;j<MAXLEN-1;j++)
            maze[i][j]=1;    //初始化迷宫
        
        for(i=1;i<MAXLEN-1;i++){
            for(j=1;j<MAXLEN-1;j++){
                int n=rand()%29;               //利用随机函数随机生成n值
                if(n<MAXLEN-1)    maze[i][j]=0;  //随机设置通道块上的不通的路块
            }
        }
        maze[1][1]=1;
        maze[MAXLEN-2][MAXLEN-2]=1;            
        return OK;            
}

void PrintMaze(MazeType &maze){ 
    int i,j;
    printf("用递增的数字代表迷宫的从入口到出口的一条路径\n");
    printf("用0代表墙和不通的地方用\n用-1代表曾走过的通道块但不通\n");
    printf("用1代表可以通过的通道块\n");
    printf("  ");
    for(i=0;i<MAXLEN;i++)  //打印列数名
        printf("%4d",i);
    printf("\n\n");
    for(i=0;i<MAXLEN;i++){
        printf("%2d",i);  //打印行名 
        for(j=0;j<MAXLEN;j++)
            printf("%4d",maze[i][j]); //输出迷宫//当前位置的标记          
        printf("\n\n");
    }
}

Status Pass(MazeType &maze,PosType curpos){
    if(maze[curpos.r][curpos.c]==1)  //可通
        return TRUE;
    else
        return FALSE;    
}

Status FootPrint(MazeType &maze,PosType curpos,int curstep){
    maze[curpos.r][curpos.c]=curstep;  //记录可通足迹
    return OK;    
}

PosType NextPos(PosType curpos,int i){
    PosType cpos=curpos;
    switch(i){        //1.2.3.4分别表示东,南,西,北方向
    case 1 : cpos.c+=1; break;
    case 2 : cpos.r+=1; break;
    case 3 : cpos.c-=1; break;
    case 4 : cpos.r-=1; break;
    default: exit(ERROR);  
    }
    return cpos;    
}

Status MarkPrint(MazeType &maze,PosType curpos){
    maze[curpos.r][curpos.c]=-1;   //-1表示曾走过但不通    
    return OK;
}

Status MazePath(MazeType &maze,PosType start,PosType end){    
    //若迷宫maze中存在从入口start到出口end的通道,则求得一条存放在栈中(从栈底到栈顶),并返回TRUE;否则返回FALSE
    SqStack S; InitStack(S); //初始化栈    
    PosType curpos=start;  //设置"当前位置"为"入口位置"    
    int curstep=1;   //探索第一步
    SElemType e;    
    do{   
        if(Pass(maze,curpos)){      //当前位置可以通过,即未曾走过的通道块
            FootPrint(maze,curpos,curstep); //留下足迹            
            e.ord=curstep; e.seat=curpos; e.di=1;
            Push(S,e);              //加入路径
            if(curpos.r==end.r && curpos.c==end.c)    return TRUE; //到达出口             
            curpos=NextPos(curpos,1); //下一位置是当前位置的东邻
            curstep++;       //探索下一步                            
        }
        else{        //当前位置不通
            if(!StackEmpty(S)){     
                Pop(S,e);
                curstep--;
                while(e.di==4 && !StackEmpty(S)){
                    MarkPrint(maze,e.seat); //留下不能通过的标记,并退一步
                    Pop(S,e);  
                    curstep--;
                }//while
                if(e.di<4){                    
                    e.di++;    //换下一个方向探索
                    Push(S,e); 
                    curstep++;
                    curpos=NextPos(e.seat,e.di);  //设定当前位置是该新方向上的相邻
                }
            }
        }
    }while(!StackEmpty(S)); 
    return FALSE;    
}

5. 主函数:
#include <stdio.h>
#include "maze.h" 
void main(){
    MazeType maze;
    PosType start,end;
    InitMaze(maze);                //初始化并创建迷宫
    start.r=1; start.c=1;          //迷宫入口坐标
    end.c=MAXLEN-2;end.r=MAXLEN-2; //迷宫出口坐标    
    PrintMaze(maze);
    if(MazePath(maze,start,end)){
        printf("存在从入口到出口的迷宫路径!\n");
        PrintMaze(maze);          //打印路径**/    
    }else printf("迷宫路径不存在!\n");    
}
【实验总结】
【实验心得】

 

栈的运用---迷宫

标签:des   style   blog   io   color   ar   os   for   sp   

原文地址:http://www.cnblogs.com/lcpholdon/p/4074852.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!