迷宫之解。

//定义状态常量
#define OVERFLOW -2
#define ERROR 0
#define NULL 0
#define true 1
#define TRUE 1
#define false 0
#define FALSE 0
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#include <stdio.h>   
#include <stdlib.h>   
/*
初始化迷宫,1表示通道,0表示墙
*/
int maze[8][8] = {
    1,1,0,1,1,1,0,1,
    1,1,0,1,1,1,0,1,
    1,1,1,1,0,0,1,1,
    1,0,0,0,1,1,1,1,
    1,1,1,0,1,1,1,1,
    1,0,1,1,1,0,1,1,
    1,0,0,0,1,0,0,1,
    0,1,1,1,1,1,1,1
};

//定义栈元素类型 
typedef struct MStackElem
{
    int x;//x坐标
    int y;//y坐标
    int val;//maze[x][y]的值
}MStackElem;

//定义栈
typedef struct {
    MStackElem * base;
    MStackElem * top;
    int stackSize;
}MStack;
//=============Stack的实现========================
//初始化栈-------构造一个空栈
void initStack(MStack *s) {
    s->base = (MStackElem *)malloc(STACK_INIT_SIZE * sizeof(MStackElem));
    if (!s->base) {
       printf("in initStack()...Failed to initalize the MStack ,no enough space! exit now. ");
       exit(OVERFLOW);//存储分配失败
    }
    s->top = s->base;
    s->stackSize = STACK_INIT_SIZE;
}

//向栈中添加元素
void push(MStack *s,MStackElem e) {
     //向栈中添加元素前先判断栈是否还有空间容纳新元素
    if (s->top - s->base >= s->stackSize) { //栈满,追加元素
       s->base = (MStackElem *)realloc(s->base, (STACK_INIT_SIZE+STACKINCREMENT) * sizeof(MStackElem));
       if (!s->base) {
        printf("in push()...Failed to realloc the MStack ,no enough space! exit now. ");
        exit(OVERFLOW);//存储分配失败
       }
       s->top = s->base + s->stackSize; /*因为是重新分配了空间,所以base的值其实已经改变,所以top的值也就相应的改变,才能指向新的迷宫栈 */
       s->stackSize += STACKINCREMENT;
    }
    //将新元素加到栈顶 
    *(s->top++) = e;
}
//获得栈顶元素
MStackElem getTop(MStack *s) {
if (s->top == s->base) {
   printf("in getTop(),empty stack! exit now. ");
   exit(ERROR);
}
else {
   return *(s->top - 1);
}
}
//删除栈顶元素
void pop(MStack *s) {
//若栈不为空,则删除s的栈顶元素
    if (s->top == s->base) {
       printf("in pop(),empty stack! exit now. ");
       exit(ERROR);
    }
    else {
       --(s->top);
    }
}

//=====================================求解迷宫的相关操作=====================//
//构造两个栈,一个用来保存探索中的全部路径,一个用来保存有效路径
MStack realPath,path;
//判断当前位置是否走过
int unPass(MStack path,MStackElem cur) {/*这里不能传path的地址,否则在遍历过程中它的top值就真的被改了 !!*/ 
    int flag = 1;
    while(path.top != path.base)
    {
       MStackElem e = *(path.top - 1);
       if (e.x == cur.x&& e.y == cur.y)
       {
        flag = 0;
       }
       //每循环一次令头指针下移一个位置 
       (path.top)--;
    }
    return flag;
}
//获得东面相邻的位置
MStackElem getEast(MStackElem cur) {
           if(cur.y != 7) {//当y==7时已到了迷宫右边界,不能再向东(右)行了 
                cur.y += 1;
                cur.val = maze[cur.x][cur.y];
           } 
           return cur;// 当y==7时返回的是它本身 
} 
//获得南面相邻的位置
MStackElem getSouth(MStackElem cur) {
           if(cur.x != 7) {//当x==7时已到了迷宫下边界,不能再向南(下)行了 
                cur.x += 1;
                cur.val = maze[cur.x][cur.y];
           }
           return cur;// 当x==7时返回的是它本身 
}
//获得西面相邻的位置
MStackElem getWest(MStackElem cur) {
           if(cur.y != 0) {//当y==0时已到了迷宫左边界,不能再向西(左)行了 
                cur.y -= 1;
                cur.val = maze[cur.x][cur.y];
           }
           return cur;// 当y==0时返回的是它本身 
}
//获得北面相邻的位置
MStackElem getNorth(MStackElem cur) {
     if(cur.x != 0) {//当cur.x==0时表示在迷宫的上边界,不能再向北(上)行了 
        cur.x -= 1;
        cur.val = maze[cur.x][cur.y];
     }
     return cur;// 当cur.x==0时返回的还是它本身 
}

//获得下一个可通行的位置,按东南西北的方向试探
MStackElem getNext(MStackElem cur) {
MStackElem next;
next.x = next.y=next.val = -1;
if(getEast(cur).val != 0 && unPass(path,getEast(cur))) {
   next = getEast(cur);
}
else if(getSouth(cur).val != 0 && unPass(path,getSouth(cur))) {
   next = getSouth(cur);
}
else if(getWest(cur).val != 0 && unPass(path,getWest(cur))) {
   next = getWest(cur);
}
else if(getNorth(cur).val != 0 && unPass(path,getNorth(cur))) {
   next = getNorth(cur);
}
//如果当前位置的四面或为墙或已走过,则返回的next的val值为-1 
return next;
}
int getMazePath(){//获得迷宫路径的函数
    MStackElem start,end,cur; 
    start.x = 0;
    start.y = 0;
    start.val = maze[start.x][start.y];
    end.x = 7;
    end.y = 7; 
    end.val = maze[end.x][end.y];
    
    cur = start; //设定当前为位置为"入口位置"
    //没有重载=运算符,可以这样用吗,结果对吗?试试吧:
    /*                                               
    printf("%d",cur.x);
    printf("%d",cur.y); 
    printf("%d",cur.val);                                                 
    */
    //恩,结果是正确的,即可以通过cur=start来把start的值赋给cur.
    /*对了,想起来了,记得以前在学C++的复制构造函数时书上好像说过, 用=(等号)复制类对象时系统会调用由系统提供的复制的构造函数什么的,*/
    //唉,记不清了,还是基础不扎实啊,以后可不能轻视基础了@_@ ...
    
    do 
    {                                                  
        if (unPass(path,cur)) {//如果当前位置未曾走到过
            push(&realPath,cur);
            push(&path,cur);
            cur = getNext(cur);
            if (cur.x == end.x && cur.y == end.y) { //到达出口了,则跳出循环,并返回true 
               //把出口结点放入路径中 
                push(&realPath,cur);
                push(&path,cur);
                //直接跳出函数(而不只是跳出这个循环 ) 
                return true;
            }
            else if(cur.val == -1) {//当前位置的四面或为墙或已走过
                 //删除真实路径的栈顶元素
                 pop(&realPath);
                 cur = getTop(&realPath);//令cur指向栈顶元素
             }
        }
       else {//如果当前位置已经走过,说明原来测试的方向不对,现在尝试其它方向
            cur = getNext(cur);
            if (cur.val == -1) {//仍不通,删除真实路径的栈顶元素
               pop(&realPath);
               cur = getTop(&realPath);//令cur指向栈顶元素
            }
       }
    } while (cur.x != end.x || cur.y != end.y);
}
//打印迷宫路径
void printMazePath(MStack *s) {/*为了安全,这里不传MStack的地址,以防在遍历的过程中把它们的top或base的值也修改了 */
     /*注:这种方法实际是倒序打印出路径,让人看着别扭,所以我用下面的方法"倒序遍历这个栈 ' 
     while (s->top != s->base) {
       MStackElem e = *(s->top-1);
       printf("maze[%d][%d]----->",e.x,e.y);
       (s->top)--;
    }
    */
     MStackElem e;
     while (s->base < (s->top-1)) {
      e = *(s->base);//先指向栈底元素,以后依次向上增1 
       printf("maze[%d][%d]----->",e.x,e.y);
       (s->base)++;
     }
     //最后一个结点没有后继,所以不再输出"------>" 
     e = *(s->base);
     printf("maze[%d][%d]",e.x,e.y);
}
main(){
      //初始化栈
    initStack(&realPath);
    initStack(&path); 
    getMazePath();
    printf("The path of through the maze is:\n\n");
    printMazePath(&realPath);
    getchar();
}

程序用的是动态数组堆栈。

考虑如下程序:

//用队列解决,感觉这里的队列和栈没什么区别
/*
* 迷宫求解
*
*/
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 50
#define M 10
int mg[M][M] ={ // 此迷宫有三条路径,需要数组外部有1围成
				{1,1,1,1,1,1,1,1,1,1},
				{1,0,0,0,1,1,1,1,1,1},
				{1,0,1,0,0,0,0,1,1,1},
				{1,0,0,1,1,1,0,1,1,1},
				{1,1,0,1,1,1,0,0,0,1},
				{1,1,0,1,1,1,1,1,0,1},
				{1,0,0,0,0,0,1,1,0,1},
				{1,0,1,1,1,0,1,1,0,1},
				{1,0,0,0,0,0,0,0,0,1},
				{1,1,1,1,1,1,1,1,1,1}
			};

// ------------------ 栈定义  -------------------------
struct{
	int i,j; // 方块的位置
	int pre; // 本路径中上一方块在路径中的下标
}Qu[MAXSIZE];

void print(int front);
/*
* 利用队列求解迷宫
*/
void mgpath(int x1, int y1, int x2, int y2)
{
	int front,rear;
	int find =0;
	int i,j;
	int di;
	front=-1;
	rear=-1;
	
	rear++; // (x1,y1)入队
	Qu[rear].i = x1;
	Qu[rear].j = y1;
	Qu[rear].pre = -1;
	
	mg[x1][y1]=-1; // 置为-1, 以免重复搜索
	while(front<=rear && !find)
	{
		front++; // 出队
		i = Qu[front].i;
		j = Qu[front].j;
		if(i == x2 && j == y2) // 出口
		{
			find = 1;
			print(front);
		}
		
		for(di=0;di<3;di++)
		{
			switch(di)
			{
				case 0:
					i=Qu[front].i - 1;
					j=Qu[front].j;
				break;
				case 1:
					i=Qu[front].i;
					j=Qu[front].j+1;
				break;
				case 2:
					i=Qu[front].i + 1;
					j=Qu[front].j;
				break;
				case 3:
					i=Qu[front].i;
					j=Qu[front].j - 1;
				break;
			}
			if(mg[i][j] == 0) // 找到
			{
				rear++; // 插入
				Qu[rear].i = i;
				Qu[rear].j = j;
				Qu[rear].pre = front;
				mg[i][j] = -1;
			} // if
		} // for
	} // while
	if(!find)
		printf("找不到可走路径");
}

void print(int front)
{
	int f,j;
	int ns=0;
	f=front;
	printf("/n");
	do{
		j = f;
	
		f = Qu[f].pre;
		Qu[j].pre = -1; //把当前的设为 -1
	}while(f!=0);
	printf("路径如下:/n");
	f=0;
	while(f<MAXSIZE)
	{
		if(Qu[f].pre==-1)
		{
			ns++;
			printf("/t(%d,%d)",Qu[f].i,Qu[f].j);
			if(ns%5 == 0)
				printf("/n");
		}
		f++;
	}
}
void main()
{
	mgpath(1,1,8,8);
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值