数据结构迷宫算法实现c语言

迷宫问题求解是一个非常经典的算法问题,该问题要求程序能根据用户的输入的长和宽去初始化迷宫,接着给用户提供两个选择,用户可以选择在迷宫里手动或自动生成指定个数的障碍,接着程序会自动找到一条能够从入口走到出口的路径,并且输出该路径

下面开始分析,因为迷宫是由多个点组成的,那么要实现上述功能,我们可以定义一个结构体去存放每个点的横纵坐标去表示位置,还需要用到一个二维数组去存放迷宫,在迷宫里有三种状态,0代表通路,1代表障碍,2代表已经走过的路,那么可以将指定的值一一赋给数组中每个元素,迷宫里的点是需要用坐标去表示的,那么为了方便,可以将二维数组下标(横坐标或纵坐标)为0的点(及迷宫的外围)都设置为1(障碍),为了防止找路时走出去,走过的路(走过的每个坐标)需要用到一个栈去存放每个点,栈其实就是一段内存,有两个指针一开始都指向数组的头地址(也能理解为栈底),接着随着数据的存放,栈顶指针会跟着存放的数据移动,栈底指针不变,那么根据这两个指针就可以随时确定栈顶元素的位置和栈的状态(空或满),因为栈这种特殊的数据结构可以保证后进入的数据先出来,所以栈在迷宫找路是可以模拟出走过的每一步以及遇到障碍时往后退的上一步位置(也就是后进入的栈顶元素),所以可以创建一个栈,里面的指针类型为定义的结构体类型

2.详细设计

首先根据用户输入的长和宽m和n用new去开辟大小为m+2(算上围墙)大小的内存,在m+2的基础上再用new开放n+2(算上围墙)大小的内存,就开辟了二维数组空间,返回的值(数组的地址)用一个二重指针去存放:具体代码如下(该函数在function.h)

int **initmaze(int &m,int &n)//用0或1输入代表迷宫,0代表通路

{

cout << "请输入迷宫的长和宽" << endl;

cout << "长度:";

cin >> m;

cout << "宽度:";

cin >> n;

cout << "请创建迷宫,0代表通路,1代表此路不通" << endl;

int **maze = new int *[n + 2];//用new,避免缓冲区溢出

for (int i = 0; i <= n + 1; i++)//创建迷宫储存空间,为迷宫设置障碍

{

maze[i] = new int[m+2];//长度加2,为迷宫周围设置障碍

}

for (int i = 0; i <= n + 1; i++)

{

maze[i][0] = maze[i][m + 1] = 1;//为每一行的第一个和最后一个元素初始化为1,为迷宫的障碍

}

for (int i = 0; i <= m + 1; i++)

{

maze[0][i] = maze[n + 1][i] = 1;//为每一列的第一个和最后一个元素初始化值为1,为迷宫障碍

}

for (int i = 1; i <= n; i++)

{

for (int j = 1; j <= m; j++)

{

maze[i][j]=0;

}

}

return maze;

}

在stack.h这个头文件定义栈这种数据结构,定义结构体position用来存放迷宫里点的坐标,代码如下:

struct position

{

int row;//行偏移

int col;//列偏移

};//定义一个结构体,用来存放位置坐标

typedef position selemtype;

typedef struct//定义栈结构为结构体栈,用来存放迷宫中某一点的横纵坐标

{

selemtype *top;//栈顶指针

selemtype *base;//栈底指针

int stacksize;

}sqstack;

定义initstack函数初始化栈,具体操作用new开辟一段内存,将这段内存的首地址赋值给top和base(两个指向position结构体类型的指针)用来表示存放路径的栈:

bool initstack(sqstack &s)//顺序栈的初始化

{

s.base = new selemtype[MAXSIZE];//为顺序栈分配空间

if (!s.base) return 0;//储存分配失败

s.top = s.base;

s.stacksize = MAXSIZE;

return 1;

}

定义一些函数去对栈进行操作

该函数将走过的点存放到栈里面,将栈顶指针重新向上移一位,指向栈顶元素

bool push(sqstack &s, selemtype e)//插入元素e为栈顶元素

{

if (s.top - s.base == s.stacksize) exit(0);//空间已满,分配失败

*s.top = e;//将值赋给栈顶指针

s.top++;//栈顶指针向上移1位

return 1;

}

该函数删除栈顶元素,即将栈顶指针向下移一位(在迷宫里表示遇到障碍退路):

bool pop(sqstack &s, selemtype &e)//删除栈顶元素

{

if (empty(s)) return 0;//栈为空,不能删除

e = *(s.top-1);//将栈顶指针减一,将栈顶元素赋给e

s.top--;

return 1;

}

该函数取得栈顶元素,及取回top指针指向的元素(在迷宫里表示退到上一位置,因为栈顶元素就是对应上一步)

该函数判断栈是否为满,根据指针位置判断

bool full(sqstack &s)//判断栈是否满了

{

if (s.top - s.base == 0)return 0;

else return 1;

}

该函数判断栈是否为空,根据指针位置判断

bool empty(sqstack &s)//判断栈是否为空

{

if (s.base == s.top)return 1;

else return 0;

}

该函数输出栈中元素,表示输出迷宫从入口到出口的路径

void stackprint(sqstack s)//输出栈中元素

{

selemtype *q;

for (q = s.base; q !=s.top; q++)

{

cout << "("<<q->row << "," <<q->col<<")"<< endl;

}

}

以上对栈的操作都放入stack.h头文件中

上述实现了迷宫需要用到的一些数据类型和数据结构

接下来分析如何实现迷宫问题

比如以下是一个迷宫,长和宽为4,旁边代表围墙,入口为(1,1),

           
           
           
           
           
           

首先要生成障碍,有两个选择,手动和自动生成,其实没区别,只需要把障碍对应的坐标设置为1即可,自动就是在指定的长宽内去生成随机数,一下为自动和手动的代码实现

int **randmaze(int **p, int &m, int &n)//随机产生障碍

{

time_t t=time(0);

srand(t);

int num, x, y;

cout << "请输入障碍物的个数"<<endl;

cin >> num;

cout << "ok,正在为你生出障碍物....请稍等" << endl;

for (int i = 0; i < num; i++)

{

x = rand() % m;//生成的随机数在指定迷宫长度的范围内,不包括出口

y = rand() % n;//生成随机数在指定迷宫宽度的范围内

p[x][y] = 1;//设置障碍

}

return p;

}

int **inputmaze(int **p, int &m, int &n)//手动输入障碍

{

int num, x, y;

cout << "请输入设置障碍物的个数" << endl;

cin >> num;

cout << "请输入障碍物的位置,行和列" << endl;

for (int i = 0; i < num; i++)

{

cout << "行:";

cin >> x;

cout << "列:";

cin >> y;

while ((x<=1 || x >=n) && (y <= 1 || y >=m))//出口入口均不能有障碍

{

cout << "输入不在范围内" << endl;

cout << "行:";

cin >> x;

cout << "列:";

cin >> y;

}

p[x][y] = 1;

}

return p;

}

设置好障碍后就开始找路,每个点都有四个选择,及向上下左右,那么可以用结构体去存放相应的偏移量,比如右偏移为行为0,列偏移为1

position offset[4];//结构体数组,存放位置偏移量

offset[0].row = 0; offset[0].col = 1;//右偏移

offset[1].row = 1; offset[1].col = 0;//下偏移

offset[2].row = 0; offset[2].col = -1;//左偏移

offset[3].row = -1; offset[3].col = 0;//上偏移

这个顺序是有要求的先向右尝试,然后是下,再左,最后上

假设生成的障碍为如下所示

           
           
           
           
           
           

先从入口(1,1)当前位置向右尝试,不行(右为1障碍),于是向下(可以,因为下个位置为0),走到(2,1),将(1,1)设为2(表示来过,防止再次走),然后将(1,1)存入栈,接着(2,2)又有4种尝试,先向右(右(2,2)为0,所以可以走)于是将(1,2)设为2表示走过并存入栈中,接着到(2,2),先向右尝试,(2,3)为1,遇到障碍,再向下尝试,还是障碍,接着上和左都不行,于是只能后退了,于是将上个位置(1,2)从栈中弹出来,将上个位置变成当前位置,接着因为(1,2)已经向右尝试过了不行,于是要从下(结构体下标为1offset[1].row = 1; offset[1].col = 0;//下偏移)开始尝试,向下可以,于是到(1,3),将(1,2)压入栈,下面都是按照上面讲的一一去尝试,直到走到出口,接着将栈输出即可,该找路部分实现代码如下

bool findpath(int **p,int &m,int &n,sqstack &path)//sqstack为存放路径的结构体栈

{

initstack(path);

position offset[4];//结构体数组,存放位置偏移量

offset[0].row = 0; offset[0].col = 1;//右偏移

offset[1].row = 1; offset[1].col = 0;//下偏移

offset[2].row = 0; offset[2].col = -1;//左偏移

offset[3].row = -1; offset[3].col = 0;//上偏移

position here;//用来存放位置

here.row = here.col = 1;

p[1][1] = 2;//入口设为2,防止在回来

int option = 0;//移动方向,根据移动方向进行不同的偏移

int lastoption = 3;

while (here.row != n||here.col != m)//没到出口

{

int r, c;

while (option <= lastoption)//依次走几个方向

{

r = here.row + offset[option].row;

c = here.col + offset[option].col;

if (p[r][c] == 0) break;//如果有通路,则跳出

option++;//否则尝试下一个方向

}

if (option <= lastoption)//如果找到方向

{

push(path, here);//将方向压入结构体栈

here.row = r;

here.col = c;

p[r][c] = 2;//将该点改为2,表示来过

option = 0;//重新设置为0,进行下一次寻路

}

else

{

position next;

if (empty(path))

{

return false;

}

next = gettop(path);//取栈顶元素,及前一点坐标

pop(path, next);//将栈顶弹出

if (here.row == next.row)//如果当前位置和上一位置行相等,说明他们在列上移

{

if (here.col > next.col)

{

option = 1;

}

else

{

option = 3;

}

//option = 2 + next.col - here.col;//下一个移动位置

}

else

{

if (here.row > next.row)

{

option = 2;

}

else

{

return false;

}

//option = 3 + next.row - here.row;//如果当前位置和上一位置列相同,说明当前位置是从行上移过来的

}

here = next;//把栈顶元素(上一位置坐标赋给当前位置,表示退回来)

}

}

return true;

}

具体代码在此贴出

#ifndef _STACK0_

#define _STACK0_

#define MAXSIZE 100

struct position

{

int row;//行偏移

int col;//列偏移

};//定义一个结构体,用来存放位置坐标

typedef position selemtype;

typedef struct//定义栈结构为结构体栈,用来存放迷宫中某一点的横纵坐标

{

selemtype *top;//栈顶指针

selemtype *base;//栈底指针

int stacksize;

}sqstack;

bool full(sqstack &s)//判断栈是否满了

{

if (s.top - s.base == 0)return 0;

else return 1;

}

bool empty(sqstack &s)//判断栈是否为空

{

if (s.base == s.top)return 1;

else return 0;

}

bool initstack(sqstack &s)//顺序栈的初始化

{

s.base = new selemtype[MAXSIZE];//为顺序栈分配空间

if (!s.base) return 0;//储存分配失败

s.top = s.base;

s.stacksize = MAXSIZE;

return 1;

}

bool push(sqstack &s, selemtype e)//插入元素e为栈顶元素

{

if (s.top - s.base == s.stacksize) exit(0);//空间已满,分配失败

*s.top = e;//将值赋给栈顶指针

s.top++;//栈顶指针向上移1位

return 1;

}

bool pop(sqstack &s, selemtype &e)//删除栈顶元素

{

if (empty(s)) return 0;//栈为空,不能删除

e = *(s.top-1);//将栈顶指针减一,将栈顶元素赋给e

s.top--;

return 1;

}

selemtype gettop(sqstack s)//获取栈顶元素的值

{

if (s.top == s.base) exit(0);

//e=*(s.top - 1);//取栈顶元素

return *(s.top-1);

}

void stackprint(sqstack s)//输出栈中元素

{

selemtype *q;

for (q = s.base; q !=s.top; q++)

{

cout << "("<<q->row << "," <<q->col<<")"<< endl;

}

}

#endif;

#ifndef _FUNCTION0_

#define _FUNCTION0_

#include<iomanip>

#include<cstdlib>//用来生成随机数

#include<ctime>

#include "stack.h"

void welcome()

{

cout << "初始化迷宫......" << endl;

}

int **initmaze(int &m,int &n)//用0或1输入代表迷宫,0代表通路

{

cout << "请输入迷宫的长和宽" << endl;

cout << "长度:";

cin >> m;

cout << "宽度:";

cin >> n;

cout << "请创建迷宫,0代表通路,1代表此路不通" << endl;

int **maze = new int *[n + 2];//用new,避免缓冲区溢出

for (int i = 0; i <= n + 1; i++)//创建迷宫储存空间,为迷宫设置障碍

{

maze[i] = new int[m+2];//长度加2,为迷宫周围设置障碍

}

for (int i = 0; i <= n + 1; i++)

{

maze[i][0] = maze[i][m + 1] = 1;//为每一行的第一个和最后一个元素初始化为1,为迷宫的障碍

}

for (int i = 0; i <= m + 1; i++)

{

maze[0][i] = maze[n + 1][i] = 1;//为每一列的第一个和最后一个元素初始化值为1,为迷宫障碍

}

for (int i = 1; i <= n; i++)

{

for (int j = 1; j <= m; j++)

{

maze[i][j]=0;

}

}

return maze;

}

int **randmaze(int **p, int &m, int &n)//随机产生障碍

{

time_t t=time(0);

srand(t);

int num, x, y;

cout << "请输入障碍物的个数"<<endl;

cin >> num;

cout << "ok,正在为你生出障碍物....请稍等" << endl;

for (int i = 0; i < num; i++)

{

x = rand() % m;//生成的随机数在指定迷宫长度的范围内,不包括出口

y = rand() % n;//生成随机数在指定迷宫宽度的范围内

p[x][y] = 1;//设置障碍

}

return p;

}

int **inputmaze(int **p, int &m, int &n)//手动输入障碍

{

int num, x, y;

cout << "请输入设置障碍物的个数" << endl;

cin >> num;

cout << "请输入障碍物的位置,行和列" << endl;

for (int i = 0; i < num; i++)

{

cout << "行:";

cin >> x;

cout << "列:";

cin >> y;

while ((x<=1 || x >=n) && (y <= 1 || y >=m))//出口入口均不能有障碍

{

cout << "输入不在范围内" << endl;

cout << "行:";

cin >> x;

cout << "列:";

cin >> y;

}

p[x][y] = 1;

}

return p;

}

void printmaze(int **p,int m,int n)

{

for (int i = 0; i <= n + 1; i++)

{

for (int j = 0; j <= m + 1; j++)

{

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

{

cout << setw(2) <<"□";

}

if (p[i][j] == 2)

{

cout << setw(2) << "○";

}

if (p[i][j] == 0)

{

cout << setw(2) << "";

}

}

cout << endl;

}

}

void delmaze(int **p, int m, int n)//销毁迷宫

{

for (int i = 0; i <= n + 1; i++)

{

delete[] p[i];

}

delete[] p;

}

bool findpath(int **p,int &m,int &n,sqstack &path)//sqstack为存放路径的结构体栈

{

initstack(path);

position offset[4];//结构体数组,存放位置偏移量

offset[0].row = 0; offset[0].col = 1;//右偏移

offset[1].row = 1; offset[1].col = 0;//下偏移

offset[2].row = 0; offset[2].col = -1;//左偏移

offset[3].row = -1; offset[3].col = 0;//上偏移

position here;//用来存放位置

here.row = here.col = 1;

p[1][1] = 2;//入口设为2,防止在回来

int option = 0;//移动方向,根据移动方向进行不同的偏移

int lastoption = 3;

while (here.row != n||here.col != m)//没到出口

{

int r, c;

while (option <= lastoption)//依次走几个方向

{

r = here.row + offset[option].row;

c = here.col + offset[option].col;

if (p[r][c] == 0) break;//如果有通路,则跳出

option++;//否则尝试下一个方向

}

if (option <= lastoption)//如果找到方向

{

push(path, here);//将方向压入结构体栈

here.row = r;

here.col = c;

p[r][c] = 2;//将该点改为2,表示来过

option = 0;//重新设置为0,进行下一次寻路

}

else

{

position next;

if (empty(path))

{

return false;

}

next = gettop(path);//取栈顶元素,及前一点坐标

pop(path, next);//将栈顶弹出

if (here.row == next.row)//如果当前位置和上一位置行相等,说明他们在列上移

{

if (here.col > next.col)

{

option = 1;

}

else

{

option = 3;

}

//option = 2 + next.col - here.col;//下一个移动位置

}

else

{

if (here.row > next.row)

{

option = 2;

}

else

{

return false;

}

//option = 3 + next.row - here.row;//如果当前位置和上一位置列相同,说明当前位置是从行上移过来的

}

here = next;//把栈顶元素(上一位置坐标赋给当前位置,表示退回来)

}

}

return true;

}

#endif;

#include<iostream>

using namespace std;

#include "function.h"

int main()

{

int m, n,t;

int **maze;

sqstack path;//用来存放路径

welcome();

maze=initmaze(m,n);//初始化函数

printmaze(maze,m,n);//输出初始化的迷宫

cout << "选择1自动生成障碍" << endl;

cout << "选择2手动创建障碍" << endl;

cin >> t;

while (t != 1 && t != 2)

{

cout << "输入错误,请重输" << endl;

cin >> t;

}

switch (t)

{

case 1:maze = randmaze(maze, m, n); break;

case 2:maze = inputmaze(maze, m, n); break;

}

cout << "迷宫如下"<<endl;

printmaze(maze,m,n);

cout << "正在寻找路径" << endl;

if (findpath(maze, m, n,path))

{

stackprint(path);

}

else

{

cout << "没有找到路径" << endl;

}

printmaze(maze,m,n);

delmaze(maze, m, n);//销毁迷宫,释放内存

return 0;

}

 
时间: 2024-08-05 19:07:15

数据结构迷宫算法实现c语言的相关文章

《数据结构与算法分析—C语言描述》pdf

下载地址:网盘下载 内容简介 编辑 <数据结构与算法分析:C语言描述(原书第2版)>内容简介:书中详细介绍了当前流行的论题和新的变化,讨论了算法设计技巧,并在研究算法的性能.效率以及对运行时间分析的基础上考查了一些高级数据结构,从历史的角度和近年的进展对数据结构的活跃领域进行了简要的概括.由于<数据结构与算法分析:C语言描述(原书第2版)>选材新颖,方法实用,题例丰富,取舍得当.<数据结构与算法分析:C语言描述(原书第2版)>的目的是培养学生良好的程序设计技巧和熟练的算

数据结构:二叉查找树(C语言实现)

数据结构:二叉查找树(C语言实现) ?写在前面 关于二叉树的基础知识,请看我的一篇博客:二叉树的链式存储 说明: 二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: 1.若其左子树不空,则左子树上所有结点的值均小于它的根结点的值: 2.若其右子树不空,则右子树上所有结点的值均大于它的根结点的值; 3.其左.右子树也分别为二叉排序树 ?二叉查找树的建立(插入): 说明: 二叉树的创建是二叉树反复插入节点所构造出来的! 若二叉树为空树,则插入元素作为树根节点. 若根结点的键值等于key,则插入失

数据结构与问题求解-Java语言描述(第三版)

数据结构对程序的重要性不言而喻,用java语言来实现常见的一些数据结构,以及在相应数据结构上的操作对学习java的同学来说是必须掌握的. 本系列博文参考<数据结构与问题求解-Java语言描述(第三版)>来实现 在自己学习的过程中,更希望有机会与大家交流. PS :本人是菜鸟,只是用博客的方式激励自己.请轻喷.Fighting!

数据结构与算法分析 c语言描述 pdf 高清下载

网盘下载:数据结构与算法分析 c语言描述 pdf 高清下载 – 易分享电子书PDF资源网 作者: [美] Mark Allen Weiss 出版社: 机械工业出版社 副标题: C语言描述 原作名: Data Structures and Algorithm Analysis in C:Second Edition 译者: 冯舜玺 出版年: 2004-1-1 页数: 391 定价: 35.00元 装帧: 平装 内容简介 · · · · · · 本书是<Data Structures and Alg

数据结构与算法 Python语言描述 笔记

数据结构 线性表包括顺序表和链表,python的list是顺序表,链表一般在动态语言中不会使用.不过链表还是会出现在各种算法题中. 链表: 单链表 双链表 循环单链表 字符串 有一个重要的点就是字符串的匹配问题,其中比较重要的是无回溯匹配算法(KMP算法),算法比较复杂,重要的思想在于匹配过程中不回溯.实际复杂度是O(m+n), m和n分别是匹配模式串和目标串,一般m<<n. 通配符 *和? * 匹配任意一个字符串 ?匹配任意一个字符 正则表达式 原始字符串:在字符串前面加r前缀,\不作为转义

数据结构与算法+Python语言描述pdf

下载地址:网盘下载 本书基于Python语言介绍了数据结构与算法的基本知识,主要内容包括抽象数据类型和Python面向对象程序设计.线性表.字符串.栈和队列.二叉树和树.集合.排序以及算法的基本知识.本书延续问题求解的思路,从解决问题的目标来组织教学内容,注重理论与实践的并用. 下载地址:网盘下载 原文地址:https://www.cnblogs.com/cf3276625841/p/9325994.html

数据结构与算法分析_Java语言描述(第2版)高清版pdf免费下载

下载地址:网盘下载 备用地址:网盘下载 内容简介编辑“数据结构”是计算机专业的基础与核心课程之一,Java是现今一种热门的语言.本书在编写过程中特别考虑到了面向对象程序设计(OOP)的思想与Java语言的特性.它不是从基于另一种程序设计语言的数据结构教材简单地“改编”而来的,因此在数据结构的实现上更加“地道”地运用了Java语言,并且自始至终强调以面向对象的方式来思考.分析和解决问题.本书是为数据结构入门课程(通常课号是CS-2)而编写的教材.作者Frank Carrano在编写过程自始至终特别

数据结构复习之C语言指针与结构体

数据结构指针复习: #include <stdio.h> void main() { int a[5] = {8, 2, 3, 4, 5}; // a[3] == *(3+a) printf("%d\n", *(3+a)); // a[3] 4 printf("*a其实就是a[0]: %d\n", *a); // 8 // 地址是连续的 printf("%p\n", a+1); printf("%p\n", a+2

数据结构之栈c语言实现

栈是一种先进后出的数据结构,计算机中常见的函数调用就用到了这种结构,其常用的操作就是出栈.入栈,如下图,数据总是从栈顶入,从栈顶出: 接下来看一个简单的程序将按"abcdef"入栈,并打印其出栈顺序: #include <stdio.h> #include <stdlib.h> #include <string.h> #define STACK_SIZE        16 #define NAME_MAX_SIZE     32 #define E