递归与非递归实现走迷宫算法
●问题描述:
给出一个矩阵,其中0表示通路,1表示墙壁,这样就形成了一个迷宫,要求编写算法求出其中一条路径。
●递归思路:
编写一个走迷宫函数,传入二位数组的下标,先假设该点位于最终路径上(将0置为2)再探测周围四个点是否可以走通(是否为0),如果可以走通则将该点四周能走通的点作为函数参数传入函数进入递归。若四周均不能走通(都不为0时)则将该点置回0表示该点不是最终路径上的点。
在此思路中递归进入时表示了枚举路径,当发现此条路径走到某处再不能走通时就将路径该点置回0并且递归退出(回溯)寻找下一条可走通路径。
●代码:
#include <stdio.h>
#include <stdlib.h>#define END_I 8
#define END_J 7
#define START_I 0
#define START_J 0//走迷宫
int VistMaze(int maze[][8], int i, int j)
{int end = 0;//假设能够走通maze[i][j] = 2;//如果到达重点则将end置为0表示迷宫已经走结束if (i == END_I && j == END_J){end = 1;}//如果迷宫没有走结束则将搜索所在位置的右、下、左、上四个方向是否能够走通if (end != 1 && j + 1 <= END_J && maze[i][j + 1] == 0){ //右if (VistMaze(maze, i, j + 1) == 1)return 1;}if (end != 1 && i + 1 <= END_I && maze[i + 1][j] == 0){ //下if (VistMaze(maze, i + 1, j) == 1)return 1;}if (end != 1 && j - 1 >= START_J && maze[i][j - 1] == 0){ //左if (VistMaze(maze, i, j - 1) == 1)return 1;}if (end != 1 && i - 1 >= START_I && maze[i - 1][j] == 0){ //上if (VistMaze(maze, i - 1, j) == 1)return 1;} //当四周都不通的时候将其置回0if (end != 1){maze[i][j] = 0;}return end;
}int main(void)
{//迷宫int i, j;int maze[9][8] = {{0,0,1,0,0,0,1,0},{0,0,1,0,0,0,1,0},{0,0,0,0,1,1,0,1},{0,1,1,1,0,0,1,0},{0,0,0,1,0,0,0,0},{0,1,0,0,0,1,0,1},{0,1,1,1,1,0,0,1},{1,1,0,0,1,1,0,1},{1,1,0,0,0,0,0,0}};//打印出迷宫printf("原迷宫:\n");for(i = 0; i <= 9; i++)printf("-");printf("\n");for (i = 0; i < 9; i++){printf("|");for (j = 0; j < 8; j++){if (maze[i][j] == 1)printf("@");elseprintf(" ");}printf("|\n");}for(i = 0; i <= 9; i++)printf("-");printf("\n");if (VistMaze(maze, 0, 0) == 0){printf("没有路径可走\n");exit(0);}//打印出迷宫和路径printf("迷宫和路径:\n");for(i = 0; i <= 9; i++)printf("-");printf("\n");for (i = 0; i < 9; i++){printf("|");for (j = 0; j < 8; j++){if (maze[i][j] == 1)printf("@");else if (maze[i][j] == 2)printf("%%");elseprintf(" ");}printf("|\n");}for(i = 0; i <= 9; i++)printf("-");printf("\n");return 0;
}
●非递归思路:
此题也可以使用栈来避开递归,首先需要开辟一个和迷宫具有同样几何形状的结构体二维数组来保存是从哪一个点(坐标)到达该点的(该初始化时将所有的坐标都置为-1),还需要一个可以保存坐标的栈。每次将能够走通的点(值为0)都入栈然后在循环的开始处将栈顶元素弹出保存进temp变量(保存坐标的变量)中,访问temp变量四周的元素是否可以被访问,如果可以被访问(值为0)则将对应路径数组中的元素(即对应坐标)值改为temp变量的值并将该能被访问的变量入栈,再将迷宫中的0(能访问)更改为2(已被访问过)防止重复访问。最后从路径数组中的出口处开始倒序输出所走路径即可。
在此种思想中栈保存了所有可以走通的点,当一个点的四周都不能够走通时弹出的该点坐标程序并没有进行任何实质性的处理,所以这就相当于一个“回溯”的过程。而访问四周的点的过程就是一个枚举的过程。
●代码:
#include <stdio.h>
#include <stdlib.h>#define COUNT_I 9
#define COUNT_J 8
#define START_I 0
#define START_J 0
#define END_I 8
#define END_J 7
#define MAXSIZE 1000//坐标位置结构体
typedef struct local{int x;int y;}LOCAL;//栈结构
typedef struct stack{LOCAL data[MAXSIZE];int top;}STACK;//初始化栈
STACK *InitStack(void)
{STACK *maze;maze = (STACK *)malloc(sizeof(STACK));maze->top = -1;return maze;
}//判栈空
int EmptyStack(STACK *maze)
{if (maze->top == -1)return 1;elsereturn 0;
}//判栈满
int IsFull(STACK *maze)
{if (maze->top == MAXSIZE - 1)return 1;elsereturn 0;}//入栈
int PushStack(STACK *maze, LOCAL *x)
{if (maze->top <= MAXSIZE - 1){maze->data[++maze->top] = *x;return 1;}else{printf("栈已满\n");return 0;}
}//出栈
int PopStack(STACK *maze, LOCAL *x)
{if (maze->top > -1){*x = maze->data[maze->top];maze->top--;return 1;}else{printf("栈已空\n");return 0;}
}//走迷宫函数
int VistMaze(int maze[][COUNT_J], LOCAL path[][COUNT_J])
{int i, j;//初始化栈STACK *stack;LOCAL temp;stack = InitStack();temp.x = 0; temp.y = 0;if (maze[START_I][START_J] == 0)PushStack(stack, &temp);elsereturn 0;while(!EmptyStack(stack)){PopStack(stack, &temp);i = temp.x; j = temp.y;maze[i][j] = 2;if (i == END_I && j == END_J)break;//下if (i + 1 <= END_I && maze[i + 1][j] == 0){maze[i + 1][j] = 2;path[i + 1][j].x = i; path[i + 1][j].y = j;temp.x = i + 1;temp.y = j;PushStack(stack, &temp);}//右if (j + 1 <= END_J && maze[i][j + 1] == 0){maze[i][j + 1] = 2;path[i][j + 1].x = i; path[i][j + 1].y = j;temp.x = i;temp.y = j + 1;PushStack(stack, &temp);}//左if (j - 1 >= 0 && maze[i][j - 1] == 0){maze[i][j - 1] = 2;path[i][j - 1].x = i; path[i][j - 1].y = j;temp.x = i;temp.y = j - 1;PushStack(stack, &temp);}//上if (i - 1 >= 0 && maze[i - 1][j] == 0){maze[i - 1][j] = 2;path[i - 1][j].x = i; path[i - 1][j].y = j;temp.x = i - 1;temp.y = j;PushStack(stack, &temp);}}//如果到达终点而退出的循环则将路径标识出来if (i == END_I && j == END_J){maze[i][j] = 3;while(path[temp.x][temp.y].x != -1){temp = path[temp.x][temp.y];maze[temp.x][temp.y] = 3;}return 1;}else{return 0;}
}int main(void)
{//迷宫int i, j;int maze[COUNT_I][COUNT_J] = {{0,0,1,0,0,0,1,0},{0,0,1,0,0,0,1,0},{0,0,0,0,1,1,0,1},{0,1,1,1,0,0,1,0},{0,0,0,1,0,0,0,0},{0,1,0,0,0,1,0,1},{0,1,1,1,1,0,0,1},{1,1,0,0,1,1,0,1},{1,1,0,0,0,0,0,0}};//定义路径数组,将到(x,y)点的路径保存进数组LOCAL path[COUNT_I][COUNT_J];for(i = 0; i < COUNT_I; i++){for(j = 0; j < COUNT_J; j++){path[i][j].x = -1;path[i][j].y = -1;}}//打印出迷宫printf("原迷宫:\n");for(i = 0; i <= COUNT_I; i++)printf("-");printf("\n");for (i = 0; i < COUNT_I; i++){printf("|");for (j = 0; j < COUNT_J; j++){if (maze[i][j] == 1)printf("@");elseprintf(" ");}printf("|\n");}for(i = 0; i <= COUNT_I; i++)printf("-");printf("\n");if (VistMaze(maze, path) == 0){printf("没有路径可走\n");exit(0);}//打印出迷宫和路径printf("迷宫和路径:\n");for(i = 0; i <= COUNT_I; i++)printf("-");printf("\n");for (i = 0; i < COUNT_I; i++){printf("|");for (j = 0; j < COUNT_J; j++){if (maze[i][j] == 1)printf("@");else if (maze[i][j] == 3)printf("%%");elseprintf(" ");}printf("|\n");}for(i = 0; i <= COUNT_I; i++)printf("-");printf("\n");return 0;
}
●心得:
这两种算法都离不开枚举与回溯这两大思想,在以后的学习中要多加理解这两种思想。在初次接触时理解不了递归的过程,后来在之上慢慢画模拟计算机的执行过程终于让递归这个过程了然于胸。可见在编程中验算是多么的重要。
递归与非递归实现走迷宫算法相关推荐
- 左神算法:分别用递归和非递归方式实现二叉树先序、中序和后序遍历(Java版)
本题来自左神<程序员代码面试指南>"分别用递归和非递归方式实现二叉树先序.中序和后序遍历"题目. 题目 用递归和非递归方式,分别按照二叉树先序.中序和后序打印所有的节点 ...
- 树的递归与非递归遍历算法
树的递归与非递归遍历算法 树的递归与非递归遍历算法 树的遍历 实例 树遍历的口诀 树的递归遍历代码 树的先序遍历 树的中序遍历 树的后序遍历 递归遍历思想 树的非递归遍历 树的先序非递归遍历 先序遍历 ...
- 二叉树的创建——递归与非递归
目录 一.知识铺垫 二.二叉树的创建之递归 三.二叉树的创建之非递归(迭代) 初学者对于二叉树的遍历(前序遍历,中序遍历,后序遍历,层序遍历),这些放在最早学习的内容,应该是非常熟悉的,但是渐渐的就会 ...
- 二叉树,二叉树的归先序遍历,中序遍历,后序遍历,递归和非递归实现
二叉树,二叉树的归先序遍历,中序遍历,后序遍历,递归和非递归实现 提示:今天开始,系列二叉树的重磅基础知识和大厂高频面试题就要出炉了,咱们慢慢捋清楚! 文章目录 二叉树,二叉树的归先序遍历,中序遍历, ...
- 二叉树的三种遍历方式(递归、非递归和Morris遍历)
二叉树的三种遍历方式(递归.非递归和Morris遍历) 原文:http://www.linuxidc.com/Linux/2015-08/122480.htm 二叉树遍历是二叉树的最基本的操作,其实现 ...
- 【Java数据结构】二叉树的前中后序遍历(递归和非递归)
二叉树的遍历 递归做法 前序遍历 中序遍历 后序遍历 非递归 前序遍历 中序遍历 后序遍历 二叉树遍历是二叉树的一种重要操作 必须要掌握 二叉树的遍历可以用递归和非递归两种做法来实现 递归做法 前序遍 ...
- 二叉树的前序、中序、后序遍历(递归、非递归写法)
文章目录 一.什么是二叉树? 二.二叉树的基本概念 三.二叉树的三种遍历方式 1.前序遍历(preordertraversal) 1.中序遍历(inordertraversal) 1.后序遍历(pos ...
- python创建树结构、求深度_数据结构-树以及深度、广度优先遍历(递归和非递归,python实现)...
前面我们介绍了队列.堆栈.链表,你亲自动手实践了吗?今天我们来到了树的部分,树在数据结构中是非常重要的一部分,树的应用有很多很多,树的种类也有很多很多,今天我们就先来创建一个普通的树.其他各种各样的树 ...
- 二叉树的几种递归和非递归式遍历:
二叉树的几种递归和非递归式遍历: 1 #include <fstream> 2 #include <iostream> 3 4 using namespace std; 5 6 ...
- 全排列(含递归和非递归的解法)
全排列在近几年各大网络公司的笔试中出现的比较频繁 首先来看看题目是如何要求的(百度迅雷校招笔试题). 用C++写一个函数, 如 Foo(const char *str), 打印出 str 的全排列, ...
最新文章
- linux ubuntu安装 mono,在Ubuntu 18.04系统中安装Mono及基本使用Mono的方法
- Gartner2014年魔力象限(商业智能和分析平台)
- 每个优秀程序员必须具备的技术技能
- wxWidgets:wxRegEx类用法
- mysql mydumper_MySQL 之mydumper安装详解
- Spring Data JPA 从入门到精通~@Modifying修改查询
- C语言课后习题(23)
- aop统计请求数量_使用SpringAOP获取一次请求流经方法的调用次数和调用耗时
- 关于github的一些问题汇总
- 同步京东、抖音、淘宝等多处订单到本地商城,这里只举例京东同步
- Signature on Pocket PC
- 机器视觉系统——照明
- winform显示器适配(解决字体模糊,界面错乱,多屏适配)
- 多态的实现机制是什么?
- mppdb 查看建表语句_MPP架构数据库优化总结——华为LibrA与GreenPlum
- springboot微软文本转语音(texttospeach) java实现微软文本转语音
- Flume OG和Flume NG的区别
- postman的命令执行工具--newman
- “猫拼狗”瓜分618,谁在玩套路?
- 平均股价的时间序列图形_求平均股价指数的公式怎么编???????