迷宫问题(堆栈及其应用)

首先我们来看看堆栈这个数据结构,像朱老师曾经说的那样堆栈是一个单腔生物,想想一个场景,有一个笔直的路,最远端是死胡同。我们现在让车一个一个的进去,那要出来的的时候必须是后进去的先出来(push和pop操作)。对于堆栈这样的数据结构有这些操作:

1.堆栈的初始化和销毁;

2.堆栈清空;

3.判断堆栈是否为空;

4.返回栈顶元素;

5.得到堆栈内元素的个数;

6.压栈与出栈;

堆栈的应用方面非常广泛,例如:数值转换,括号匹配,行编辑程序,迷宫问题和表达式等。

无论是那种应用,都要记住堆栈的最大的功能是:记忆!!!

下面是堆栈的代码,我这个里面没有判断堆栈是否为满,如果堆栈元素等于申请个数时,堆栈会追加10个元素,这个可以修改。让对内存的申请达到合适的数量。如果要用堆栈时,把头文件预处理就行了。

一.  STACK.H

#ifndef _STACK_H_

#define _STACK_H_

#include<malloc.h>

#include<stdlib.h>

#define TRUE 1

#define FALSE 0

#define STACKINCREMENT
10

typedef struct STACK

{

USER_TYPE *top;
//栈顶指针

USER_TYPE *base;
//栈底指针

int maxRoom;

}STACK;

typedef unsigned char Boolean;

STACK *initStack(int maxRoom);
//初始化堆栈

void destroyStack(STACK **sta);
//销毁堆栈

Boolean isStackEmpty(STACK sta);
//判断堆栈是否为空

void clearStack(STACK *sta);
//清空堆栈信息

int stackLength(STACK sta);
//返回堆栈内元素个数

Boolean getStackTop(STACK sta, USER_TYPE *element);
//得到栈顶元素

Boolean push(STACK *sta, USER_TYPE element);
//入栈

Boolean pop(STACK *sta, USER_TYPE *element);
//出栈

Boolean pop(STACK *sta, USER_TYPE *element)

{

Boolean OK = TRUE;

if(isStackEmpty(*sta) == FALSE)

{

*element = *(sta->top - 1);

sta->top--;

}

else

{

OK = FALSE;

}

return OK;

}

Boolean push(STACK *sta, USER_TYPE element)

{

Boolean OK = TRUE;

if( (sta->top - sta->base) >= sta->maxRoom)

{

sta->base = (USER_TYPE *)realloc(sta->base,

(sta->maxRoom + STACKINCREMENT) * sizeof(USER_TYPE));

if(sta->base == NULL)

{

exit(1);
//存储分配失败

}

sta->top = sta->base + sta->maxRoom;

sta->maxRoom += STACKINCREMENT;

}

*sta->top = element;

sta->top++;

return OK;

}

Boolean getStackTop(STACK sta, USER_TYPE *element)

{

Boolean OK = TRUE;

if(isStackEmpty(sta) == FALSE)

{

*element = *(sta.top - 1);

}

else

{

OK = FALSE;

}

return OK;

}

int stackLength(STACK sta)

{

return sta.top - sta.base;

}

void clearStack(STACK *sta)

{

sta->top = sta->base;

}

Boolean isStackEmpty(STACK sta)

{

return sta.top == sta.base;

}

void destroyStack(STACK **sta)

{

if((*sta)->base)

free((*sta)->base);

(*sta)->top = NULL;

free(*sta);

}

STACK *initStack(int maxRoom)

{

STACK *stack;

stack = (STACK *)malloc(sizeof(STACK));

if(stack == NULL)

{

exit(1);

}

else

{

stack->maxRoom = maxRoom;

stack->base = (USER_TYPE *)malloc(sizeof(USER_TYPE) * maxRoom);

if(stack->base == NULL)

{

exit(0);

}

stack->top = stack->base;

}

return stack;

}

#endif

二. 迷宫问题

迷宫问题跟那个电老鼠有很多相似之处,但只是在软件级别上的问题,简单了不少。迷宫问题要解决一下几个方面:

1.如何存储合理位置的信息(当然是用堆栈了);

2.移动方向的判断(这个和醉酒螳螂有着极大的相似之处,还是把八个方向用一个结构体数组存储,看来这个方法经常用啊);

3.不可以在迷宫上直接操作,需要用另外一个二维数组动态显示位置变化;

还需解决的问题:

如何动态的生成一个迷宫?以后再看;

迷宫搜索算法有没有比单方向查找更快的方法?大家一起看;

迷宫的代码就摆出来了。。。

/*

迷宫问题:使用到了堆栈,原理是对的,但是在显示的时候太过狗血,而且路径没有正向输出,大家凑活着看吧。。。。

*/

#include<stdio.h>

#include<conio.h>

#include<windows.h>

typedef struct OFFSETS

{

short int vert;
//横方向

short int horiz;
//纵方向

}OFFSETS;

//要保存的每个节点信息

typedef struct element

{

short int row;

short int col;

short int direct;

}element;

typedef element USER_TYPE;

#include"STACK.H" //堆栈

#define MAZE_ROWS 11
//迷宫行数

#define MAZE_COLS 15
//迷宫列数

#define BOUNDARY_COLS
17 //边界列数

#define BOUNDARY_ROWS
13 //边界行数

#define FALSE 0

#define TRUE 1

//生成一个迷宫的图形(这尼玛是要累死人啊!!!)

static short int maze[BOUNDARY_ROWS][BOUNDARY_COLS] =

{

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1},

{1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1},

{1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1},

{1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1},

{1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1},

{1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1},

{1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1},

{1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1},

{1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1},

{1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1},

{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},

};

//该矩阵是为了记录已经检查过的迷宫位置,元素初始化都为0

static short int mark[BOUNDARY_ROWS][BOUNDARY_COLS] = {0};

OFFSETS move[8]; /*当前点对应的八个方向*/

STACK *nodeStack;

void initMove(void);
//初始化各方向

void showMaze(void);
//显示迷宫

void foundPath(); //寻找路径

void printOneNode(int row, int col, int direct);
//打印一个节点

void showMark(void);
//显示路径

void showMark(void)

{

int i, j;

for(i = 0; i < BOUNDARY_ROWS; i++)

{

for(j = 0; j < BOUNDARY_COLS; j++)

if(mark[i][j] == 1)

printf("%3c", 5);

else

printf("%3c", 3);

printf("\n");

}

}

void printOneNode(int row, int col, int direct)

{

printf("%2d    %2d%5d", direct, row, col);

switch(direct - 1)

{

case 0:

printf("    北边");

break;

case 1:

printf("    东北");

break;

case 2:

printf("    东边");

break;

case 3:

printf("    东南");

break;

case 4:

printf("    南边");

break;

case 5:

printf("    西南");

break;

case 6:

printf("    西边");

break;

case 7:

printf("    西北");

break;

}

printf("\n");

}

void foundPath()

{

int i, row, col, nextRow, nextCol, direct, count;

int found = FALSE;
//初始化为没有找到出口

USER_TYPE
position;

mark[1][1] = 1;
//开始处于(1,1)迷宫入口

position.row = 1, position.col = 1, position.direct = 0;

push(nodeStack, position);

//节点栈不为空并且没有找到出口

while(isStackEmpty(*nodeStack) == FALSE && found == FALSE)

{

pop(nodeStack, &position);

row = position.row;

col = position.col;

direct = position.direct;

while(direct < 8 && found == FALSE)

{

nextRow = row + move[direct].vert;

nextCol = col + move[direct].horiz;

//如果找到了出口

if(nextRow == MAZE_ROWS + 1 && nextCol == MAZE_COLS + 1)

found = TRUE;

//当前点没有被检查过

else if(!maze[nextRow][nextCol]

&& !mark[nextRow][nextCol])

{

mark[nextRow][nextCol] = 1;

position.row = row;

position.col= col;

position.direct = ++direct;

push(nodeStack, position);
//将这个节点保存

row = nextRow;

col = nextCol;

direct = 0;

system("cls");

showMaze();

printf("\n");

printf("上一个图为迷宫图,下一个图是寻找路径的过程\n");

showMark();

Sleep(200);
//停顿一秒

}

else

direct++;
//换个方向测试

}

}

if(found == FALSE)

printf("该迷宫没有路径可以出去!");

else

{

count = stackLength(*nodeStack);

printf("该迷宫的出口路径是:\n\n");

printf("dir#  rol  col  direct\n\n");

//打印出路径

for(i = 0; i < count; i++)

{

pop(nodeStack, &position);

printOneNode(position.row, position.col, position.direct);

}

}

}

void showMaze(void)

{

int i, j;

for(i = 0; i < BOUNDARY_ROWS; i++)

{

for(j = 0; j < BOUNDARY_COLS; j++)

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

printf("%3c", 3);

else

printf("%3c", 5);

printf("\n");

}

}

void initMove(void)

{

move[0].vert = -1, move[0].horiz = 0;
/* 北边 */

move[1].vert = -1, move[1].horiz = 1;
/* 东北 */

move[2].vert = 0, move[2].horiz = 1;
/* 东边 */

move[3].vert = 1, move[3].horiz = 1;
/* 东南 */

move[4].vert = 1, move[4].horiz = 0;
/* 南边 */

move[5].vert = 1, move[5].horiz = -1;
/* 西南 */

move[6].vert = 0, move[6].horiz = -1;
/* 西边 */

move[7].vert = -1, move[7].horiz = -1;
/* 西北 */

}

int main(int argc, char **argv)

{

nodeStack = initStack(20);
//初始化堆栈(起始数量为20个,如果堆栈内元素判满时,自动追加10个元素)

initMove();
//初始化各方向

showMaze();
//显示迷宫

foundPath();
//寻找路径

destroyStack(&nodeStack);

getch();

return 0;

}

关于堆栈的用法肯定会是多种多样的,咱们一起来探索。

迷宫问题(堆栈及其应用)

时间: 2024-11-05 06:26:02

迷宫问题(堆栈及其应用)的相关文章

迷宫问题 - 堆栈与深度优先搜索

堆栈的访问规则被限制为Push和Pop两种操作,Push(入栈或压栈)向栈顶添加元素,Pop(出栈或弹出)则取出当前栈顶的元素,也就是说,只能访问栈顶元素而不能访问栈中其它元素. 现在我们用堆栈解决一个有意思的问题,定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; 它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走

堆栈应用(六):迷宫搜索

1.问题描述 迷宫( m a z e)是一个矩形区域,它有一个入口和一个出口.在迷宫的内部包含不能穿越的墙或障碍.在图 5 - 8所示的迷宫中,障碍物沿着行和列放置,它们与迷宫的矩形边界平行.迷宫的入口在左上角,出口在右下角.图5-8 迷宫假定用 n× m的矩阵来描述迷宫,位置 ( 1 , 1 )表示入口, (n,m) 表示出口, n和m分别代表迷宫的行数和列数.迷宫中的每个位置都可用其行号和列号来指定.在矩阵中,当且仅当在位置(i,j)处有一个障碍时其值为 1 ,否则其值为 0.图 5 - 9

如何找到迷宫出口

一.问题描述 给出如下的矩阵 1 1 1 1 0 0 0 1 1 9 0 0 1 1 1 1 其中1代表此位置是可以通过的,0代表此位置是不可通过的,要从起点开始,确定是否存在这样一条路径,可以从起点找到数字9.也就是找到这样一条路径1->1->1 ...... ->9.这个问题是寻找迷宫出口的变形.可以将9看成是迷宫的出口,而给出的开始位置是迷宫的入口,寻找一条路径. 二.问题求解 当矩阵阶数不是太大的时,可以使用递归来求解,但是,当矩阵的阶数变得很大时,则需要使用另外的方法进行计算,

AI-随机迷宫&amp;迷宫求解

本文记录了,人工智能中简单的搜索策略中的路径搜索策略中的A*算法,来实现迷宫寻路的问题.(这只是一次本人的课外作业) 完整的程序源码已经发送到我的Git.这里只记录了我的思路和感想以及收获. 产生随机迷宫 迷宫求解没有迷宫怎么可以呢.而本人是个懒人,每次都要手动输入迷宫,重复性的工作让我很不爽.你可以在程序中用数组定义一个迷宫啊,有强迫症的我,怎么可以这样随便的要求自己的程序呢.及时求解算法的出来了,但是测试数据有限,还是让我很不爽的,所以,干脆先花一些时间,写个随机迷宫的产生吧. 遇事先搜索,

回溯法找迷宫最短路径

有一个二维数组,0表示路,-1表示墙,求其中任意两点的最短路径 我们先看,怎么求一条路径:求两点路径是一个数据结构上的典型的迷宫问题,解决办法如下: 从一点开始出发,向四个方向查找(上,右,下,左),每走一步,把走过的点的值+1,防止重复行走,并把走过的点压入堆栈(表示路径),如果遇到墙.或者已走过的点则不能前进,如果前方已经无路可走,则返回,路径退栈,这样递归调用,直到找到终点为止. 如果我们调整查找的顺序,改为左.右.上.下,可能会得到更短的路径,但这种方法不能保证一定是最短路径. 经过网上

Java数据结构之回溯算法的递归应用迷宫的路径问题

一.简介 回溯法的基本思想是:对一个包括有很多结点,每个结点有若干个搜索分支的问题,把原问题分解为对若干个子问题求解的算法.当搜索到某个结点.发现无法再继续搜索下去时,就让搜索过程回溯(即退回)到该结点的前一结点,继续搜索这个结点的其他尚未搜索过的分支:如果发现这个结点也无法再继续搜索下去时,就让搜索过程回溯到这个结点的前一结点继续这样的搜索过程:这样的搜索过程一直进行到搜索到问题的解或搜索完了全部可搜索分支没有解存在为止. 该方法可以使用堆栈实现.也可以使用递归实现,递归实现的话代码比较简单,

迷宫问题的求解方式:应用深度优先和广度优先的搜索

用堆栈实现迷宫问题,二维数组表示迷宫:1表示墙壁,0表示可以走的路,只能横着走或竖着走 不能斜着走,要求编程实现找到从左上角到右下角的路线 //深度优先:有解就退出搜索(不一定是最优解) #include<iostream> #include<stdio.h> using namespace std; #define ROW 5 #define COL 5 typedef struct point { int _row; int _col; }Point; Point stack[

从迷宫问题、连连看、红与黑说回溯算法遍历解空间

今天上午完成了“迷宫”问题,也思考了“2.5基本算法之搜索”的另外几个问题:小游戏(就一连连看),马走日,红与黑等.我所关注的这几个问题都可以用回溯算法来进行解决.回溯算法简单说就是当运行到叶子节点证明不是解时回到上一层节点继续遍历,如此循环直到找到一个解:如果需要全部解,可以继续遍历,如果不需要可以直接退出.很明显,回溯算法是一种深度优先的搜索算法,非常适合在解空间中找到一个解的问题. 一.迷宫问题: 1792:迷宫 总时间限制: 3000ms 内存限制: 65536kB 描述 一天Exten

学习日志---递归、非递归,迷宫问题

递归算法的设计方法: 适宜于用递归算法求解的问题的充分必要条件是: (1)问题具有某种可借用的类同自身的子问题描述的性质    (2)某一有限步的子问题(也称作本原问题)有直接的解存在.当一个问题存在上述两个基本要素时,设计该问题的递归算法的方法是:   (1)把对原问题的求解表示成对子问题求解的形式.   (2)设计递归出口. 阶乘: import java.util.Scanner; public class JieChengDemo {     public static long jie