第 3 章 栈和队列(顺序栈,算法 3.3)

1. 背景说明:

若迷宫 maze 中存在从入口 start 到出口 end 的通道,则求得一条存放在栈中(从栈底到栈顶),并返回 TRUE;否则返回 FALSE,注意,该解并非最优解,

最优解需要求得最短路径且可能并非一条。

迷宫示意图:

    输入文本:

 

10 10181 3
1 7
2 3
2 7
3 5
3 6
4 2
4 3
4 4
5 4
6 2
6 6
7 2
7 3
7 4
7 6
7 7
8 11 18 8

2. 示例代码

1) status.h

/* DataStructure 预定义常量和类型头文件 */#ifndef STATUS_H
#define STATUS_H/* 函数结果状态码 */
#define TRUE 					1			/* 返回值为真 */
#define FALSE 					0			/* 返回值为假 */
#define RET_OK 					0			/* 返回值正确 */
#define INFEASIABLE    		   	2			/* 返回值未知 */
#define ERR_MEMORY     		   	3			/* 访问内存错 */
#define ERR_NULL_PTR   			4			/* 空指针错误 */
#define ERR_MEMORY_ALLOCATE		5			/* 内存分配错 */
#define ERR_NULL_STACK			6			/* 栈元素为空 */
#define ERR_PARA				7			/* 函数参数错 */
#define ERR_OPEN_FILE			8			/* 打开文件错 */
typedef int Status;							/* Status 是函数的类型,其值是函数结果状态代码,如 OK 等 */
typedef int Bollean;						/* Boolean 是布尔类型,其值是 TRUE 或 FALSE */#endif // !STATUS_H

2) sqStack.h

/* 栈的顺序存储表示头文件 */#ifndef SQSTACK_H
#define SQSTACK_H#include "status.h"#define STACK_INIT_SIZE 10 		/* 存储空间初始分配量 */
#define STACKINCREMENT 2 		/* 存储空间分配增量 *//* 迷宫位置坐标 */
typedef struct {int x;int y;
} MazePosition;/* 定义栈元素类型 */
typedef struct {int order;					/* 通道块在路径上的序号 */int direction;				/* 下一块路径的方向,取值为 0 ~ 3, 分别表示上下左右 */MazePosition pos;			/* 当前通道块在迷宫中的坐标位置 */
} SElemType;typedef struct SqStack {SElemType* base; 			/* 在栈构造之前和销毁之后,base的值为NULL */SElemType* top; 			/* 栈顶指针 */int stackSize; 				/* 当前已分配的存储空间,以元素为单位 */
} SqStack; 						/* 顺序栈 *//* 构造一个空栈 S */
Status InitStack(SqStack* S);/* 销毁栈 S */
void DestroyStack(SqStack* S);/* 把 S 置为空栈 */
void ClearStack(SqStack* S);/* 若栈 S 为空栈,则返回 TRUE,否则返回 FALSE */
Status StackEmpty(SqStack S);/* 返回 S 的元素个数,即栈的长度 */
int StackLength(SqStack S);/* 若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;否则返回 ERROR */
Status GetTop(SqStack S, SElemType* e);/* 插入元素 e 为新的栈顶元素 */
Status Push(SqStack* S, SElemType e);/* 若栈不空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR */
Status Pop(SqStack* S, SElemType* e);/* 从栈底到栈顶依次对栈中每个元素调用函数 visit() */
void StackTraverse(SqStack S, void(*Visit)(SElemType));#endif

3) sqStack.c

/* 栈的顺序存储表示源文件 */#include "sqStack.h"
#include "status.h"
#include <stdlib.h>
#include <stdio.h>/* 构造一个空栈 S */
Status InitStack(SqStack* S)
{(*S).base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));if (!(*S).base) {printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);return ERR_MEMORY_ALLOCATE;}(*S).top = (*S).base;(*S).stackSize = STACK_INIT_SIZE;return RET_OK;
}/* 销毁栈 S */
void DestroyStack(SqStack* S)
{free((*S).base);(*S).base = NULL;(*S).top = NULL;(*S).stackSize = 0;
}/* 把 S 置为空栈 */
void ClearStack(SqStack* S)
{(*S).top = (*S).base;
}/* 若栈 S 为空栈,则返回 TRUE,否则返回 FALSE */
Status StackEmpty(SqStack S)
{return (S.top == S.base) ? TRUE : FALSE;
}/* 返回 S 的元素个数,即栈的长度 */
int StackLength(SqStack S)
{return (int)(S.top - S.base);
}/* 若栈不空,则用 e 返回 S 的栈顶元素,并返回 OK;否则返回 ERROR */
Status GetTop(SqStack S, SElemType* e)
{if (S.top > S.base) {*e = *(S.top - 1);return RET_OK;}printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_NULL_STACK);return ERR_NULL_STACK;
}/* 插入元素 e 为新的栈顶元素 */
Status Push(SqStack* S, SElemType e)
{if (((*S).top - (*S).base) == (*S).stackSize) {(*S).base = (SElemType*)realloc((*S).base, (unsigned long long)(((*S).stackSize) + STACKINCREMENT) * sizeof(SElemType));if (!(*S).base) {printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);return ERR_MEMORY_ALLOCATE;}(*S).top = (*S).base + (*S).stackSize;(*S).stackSize += STACKINCREMENT;}*((*S).top)++ = e;return RET_OK;
}/* 若栈不空,则删除 S 的栈顶元素,用 e 返回其值,并返回 OK;否则返回 ERROR */
Status Pop(SqStack* S, SElemType* e)
{if ((*S).top == (*S).base) {printf("FuncName: %-15s Line: %-5d ErrorCode: %-3d\n", __func__, __LINE__, ERR_MEMORY_ALLOCATE);return ERR_MEMORY_ALLOCATE;}*e = *(--(*S).top);return RET_OK;
}/* 从栈底到栈顶依次对栈中每个元素调用函数 visit() */
void StackTraverse(SqStack S, void(*Visit)(SElemType))
{while (S.top > S.base) {Visit(*S.base++);}
}

4) algorithm.h

/* 算法定义头文件 */
#ifndef ALGORITHM_H
#define ALGORITHM_H#include "sqStack.h"
#include "status.h"#define MAXLENGTH 25			/* 设迷宫最大行列为 25 *//* 定义墙元素值为 0,可通过路径为 -2, 不能通过路径为 -1 */
typedef int MazeType[MAXLENGTH][MAXLENGTH];/* 算法 3.3, 若迷宫 maze 中存在从入口 start 到出口 end 的通道,则求得第一条路径存放在栈中(从栈底到栈顶),并返回 TRUE;否则返回 FALSE */
Status MazePath(MazePosition start, MazePosition end, MazeType* maze, int* totalStep);/* 如果存在路径,输出求得的迷宫的解 */
void PrintMazePath(int row, int col, MazeType* maze);#endif // !ALGORITHM_H

5) algorithm.c

/* 算法实现源文件 */#include "algorithm.h"
#include <string.h>
#include <stdio.h>/*  定义墙元素值为 0,可通过路径为 -2, 不能通过路径为 -1,通过路径为足迹当迷宫 maze 的 curPos 点的序号为 -2(可通过路径),return OK; 否则,return FALSE */
static Bollean PassPos(MazePosition curPos, MazeType* maze)
{return ((*maze)[curPos.x][curPos.y] == -2) ? TRUE : FALSE;
}/* 使迷宫 maze 的 curPos 点的序号变为足迹 totalStep */
static void FootPrint(MazePosition curPos, MazeType* maze, int* totalStep)
{(*maze)[curPos.x][curPos.y] = *totalStep;
}/* 根据当前位置及移动方向,返回下一位置 */
static MazePosition NextPos(MazePosition curPos, int direction)
{	/* 上下左右四个方向的行、列增量 */MazePosition direc[4] = { { -1, 0 }, { 1 , 0 }, { 0, -1 }, { 0, 1 } };curPos.x += direc[direction].x;curPos.y += direc[direction].y;return curPos;
}/* 使迷宫 maze 的 curPos 点的序号变为 -1(不能通过的路径) */
static void MarkPrint(MazePosition curPos, MazeType* maze)
{(*maze)[curPos.x][curPos.y] = -1;
}/* 判断两个位置是否相同,相同返回 TRUE, 否则返回 FALSE */
static Bollean PostionSame(MazePosition pos1, MazePosition pos2)
{return ((pos1.x == pos2.x) && (pos1.y == pos2.y)) ? TRUE : FALSE;
}/* 算法 3.3, 若迷宫 maze 中存在从入口 start 到出口 end 的通道,则求得一条存放在栈中(从栈底到栈顶),并返回 TRUE;否则返回 FALSE */
Status MazePath(MazePosition start, MazePosition end, MazeType* maze, int* totalStep)
{SqStack S = { 0 };InitStack(&S);MazePosition curPos = { 0 };(void)memcpy_s(&curPos, sizeof(MazePosition), &start, sizeof(MazePosition));SElemType sE = { 0 };do {if (PassPos(curPos, maze)) {FootPrint(curPos, maze, totalStep);sE.order = *totalStep;sE.pos.x = curPos.x;sE.pos.y = curPos.y;sE.direction = 0;++(*totalStep);Push(&S, sE);if (PostionSame(curPos, end)) {return TRUE;}curPos = NextPos(curPos, sE.direction);} else {if (!StackEmpty(S)) {Pop(&S, &sE);--(*totalStep);while ((sE.direction == 3) && (!StackEmpty(S))) {MarkPrint(sE.pos, maze);Pop(&S, &sE);--(*totalStep);}if (sE.direction < 3) {++(sE.direction);Push(&S, sE);++(*totalStep);curPos = NextPos(sE.pos, sE.direction);}}}} while (!StackEmpty(S));return FALSE;
}/* 如果存在路径,输出求得的迷宫的解 */
void PrintMazePath(int row, int col, MazeType* maze)
{for (int i = 0; i < row; ++i) {for (int j = 0; j < col; ++j) {printf("%3d", (*maze)[i][j]);}printf("\n");}
}

6) main.c

/* 入口程序源文件 */#include "status.h"
#include "algorithm.h"
#include <stdio.h>int main(void)
{printf("Please input the row and col of the maze: ");int row = 0, col = 0;scanf_s("%d%d", &row, &col);MazeType maze = { 0 };for (int i = 0; i < col; ++i) {maze[0][i] = 0;maze[row - 1][i] = 0;}for (int i = 1; i < row - 1; ++i) {maze[i][0] = 0;maze[i][row - 1] = 0;}for (int i = 1; i < row - 1; ++i) {for (int j = 1; j < col - 1; ++j) {maze[i][j] = -2;}}printf("Please input the num of the wall: ");int wallNum = 0;scanf_s("%d", &wallNum);printf("Please input the position of the wall(x, y): \n");int x = 0, y = 0;for (int i = 0; i < wallNum; ++i) {scanf_s("%d%d", &x, &y);maze[x][y] = 0;}printf("The structure of the maze is:\n");PrintMazePath(row, col, &maze);MazePosition start = { 0 }, end = { 0 };printf("Please input the position of the start point(x, y):");scanf_s("%d%d", &start.x, &start.y);printf("Please input the position of the end point(x, y):");scanf_s("%d%d", &end.x, &end.y);int totalStep = 1;if (MazePath(start, end, &maze, &totalStep)) {printf("Use %d steps, one of the path from start to end of the maze is:\n", --totalStep);PrintMazePath(row, col, &maze);} else {printf("There is no way to the end.\n");}return 0;
}

3. 输出示例:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/112800.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

源码角度看待线程池的执行流程

文章目录 前言一、线程池的相关接口和实现类1.Executor接口2.ExecutorService接口3.AbstractExecutorService接口4.ThreadPoolExecutor 实现类 二、ThreadPoolExecutor源码解析1.Worker内部类2.execute()方法3.addWorker()方法 总结 前言 线程池内部维护了若干个线程&#xff…

C++笔记之静态成员函数可以在类外部访问私有构造函数吗?

C笔记之静态成员函数可以在类外部访问私有构造函数吗&#xff1f; 参考笔记&#xff1a; 1.C笔记之静态成员函数可以在类外部访问私有构造函数吗&#xff1f; 2.C笔记之设计模式&#xff1a;setter函数、依赖注入 3.C笔记之两个类的实例之间传递参数——通过构造函数传递类对象…

Springboot集成Docker并将镜像推送linux服务器

案例使用springboot项目&#xff0c;在IDEA 中集成Docker生成镜像&#xff0c;并将镜像发布到linux服务器 具体步骤如下&#xff1a; 1、Centos7安装Docker 更新系统的软件包列表 sudo yum update安装Docker所需的软件包和依赖项&#xff1a; sudo yum install docker完成…

说说FLINK细粒度滑动窗口如何处理

分析&回答 Flink的窗口机制是其底层核心之一&#xff0c;也是高效流处理的关键。Flink窗口分配的基类是WindowAssigner抽象类&#xff0c;下面的类图示出了Flink能够提供的所有窗口类型。 Flink窗口分为滚动&#xff08;tumbling&#xff09;、滑动&#xff08;sliding&am…

postgresql-子查询

postgresql-子查询 简介派生表IN 操作符ALL 操作符ANY 操作符关联子查询横向子查询EXISTS 操作符 简介 子查询&#xff08;Subquery&#xff09;是指嵌套在其他 SELECT、INSERT、UPDATE 以及 DELETE 语句中的 查询语句。 子查询的作用与多表连接查询有点类似&#xff0c;也是为…

NTP时钟同步服务器

目录 一、什么是NTP&#xff1f; 二、计算机时间分类 三、NTP如何工作&#xff1f; 四、NTP时钟同步方式&#xff08;linux&#xff09; 五、时间同步实现软件&#xff08;既是客户端软件也是服务端软件&#xff09; 六、chrony时钟同步软件介绍 七、/etc/chrony.conf配置文件介…

JVM内存管理、内存分区:堆、方法区、虚拟机栈、本地方法栈、程序计数器

内存管理 内存分区 线程共享 堆 存放实例&#xff0c;字符串常量&#xff08;直接引用&#xff09;&#xff0c;静态变量&#xff0c;线程分配缓冲区&#xff08;TLAB线程私有&#xff09;。垃圾收集器管理的区域 方法区 非堆&#xff0c;和堆相对的概念。存储已被虚拟机加载的…

uniapp的 picker 日期时间选择器

效果图&#xff1a; dateTimePicker.js function withData(param){return param < 10 ? 0 param : param; } function getLoopArray(start,end){var start start || 0;var end end || 1;var array [];for (var i start; i < end; i) {array.push(withData(i))…

【ACM出版】第四届人工智能与计算工程国际学术会议(ICAICE 2023)

ACM出版|第四届人工智能与计算工程国际学术会议 The 4th International Conference on Artificial Intelligence and Computer Engineering 为了在人工智能技术应用与计算工程领域进一步的探索&#xff0c;与国内外学界和业界相关人员交流新问题、新发现、新成果、新应用&…

__call__函数

一、定义 在Python中&#xff0c;__call__函数是一个特殊的方法&#xff0c;用于使一个对象可以像函数一样被调用。当一个对象定义了__call__方法时&#xff0c;它就成为了一个可调用对象。 二、使用 class Counter:def __init__(self):self.count 0def __call__(self):sel…

查局域网所有占用IP

查局域网所有占用IP 按&#xff1a;winr 出现下面界面&#xff0c;在文本框中输入 cmd 按确定即可出现cmd命令界面 在cmd命令窗口输入你想要ping的网段&#xff0c;下面192.168.20.%i即为你想要ping的网段&#xff0c;%i代表0-255 for /L %i IN (1,1,254) DO ping -w 1 -n 1…

优化物料编码规则,提升物料管理效率

导 读 ( 文/ 2358 ) 物料是生产过程的必需品。对物料进行身份的唯一标识&#xff0c;可以更好的管理物料库存、库位&#xff0c;更方便的对物料进行追溯。通过编码规则的设计&#xff0c;可以对物料按照不同的属性、类别或特征进行分类&#xff0c;从而更好地进行库存分析、计划…

业务需要咨询?开发遇到 bug 想反馈?开发者在线提单功能上线!

大家是否遇到过下列问题—— 在开发的时候&#xff0c;遇到 bug 需要反馈… 有合作意向的时候&#xff0c;想更多了解业务和相关产品… 在接入的时候&#xff0c;需要得到专业技术支持… 别急&#xff0c;荣耀开发者服务平台在线提单功能上线了~ 处理问题分类说明&#xff1…

ElasticSearch(一)数据类型

ElasticSearch&#xff08;一&#xff09;数据类型 1.简述 Es数据类型分为基础数据类型和复杂类型数据&#xff0c;掌握ES数据类型才能进一步使用ES检索数据内容。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot…

阿里云申请免费SSL证书的两种验证方式及配置服务器Tomcat升级HTTPS协议

通用教程&#xff0c;其他服务商的免费 SSL 证书也差不多是这个流程。&#xff08;至少腾讯云的操作步骤和本文是一致&#xff0c;嘻嘻&#xff01;&#xff09; 申请 SSL 证书 首先在阿里云上创建并申请 SSL 证书&#xff0c;之后选择 DNS 验证的方式&#xff0c;一种是手动配…

【Go 基础篇】Go语言结构体详解:打开自定义类型的大门

嗨&#xff0c;Go语言学习者们&#xff01;在编程的世界里&#xff0c;数据是核心&#xff0c;而结构体&#xff08;Struct&#xff09;是一种能够帮助我们更有组织地存储和操作数据的重要工具。在本篇博客中&#xff0c;我们将深入探讨Go语言中结构体的概念、定义、初始化、嵌…

PYTHON链家租房数据分析:岭回归、LASSO、随机森林、XGBOOST、KERAS神经网络、KMEANS聚类、地理可视化...

全文下载链接:http://tecdat.cn/?p29480 作者&#xff1a;Xingsheng Yang 1 利用 python 爬取链家网公开的租房数据&#xff1b; 2 对租房信息进行分析&#xff0c;主要对房租相关特征进行分析&#xff0c;并搭建模型用于预测房租&#xff08;点击文末“阅读原文”获取完整代码…

自动化运维:Ansible脚本之playbook剧本

目录 一、理论 1.playbooks 2.YAML 3.使用ansible批量安装apache服务 4.定义、引用变量 5.指定远程主机sudo切换用户 6.when条件判断 7.迭代 8.Templates 模块 9.tags 模块 10.Roles 模块 二、实验 1.使用ansible批量安装apache服务 2.定义、引用变量…

k8s之存储篇---数据卷Volume

数据卷概述 Kubernetes Volume&#xff08;数据卷&#xff09;主要解决了如下两方面问题&#xff1a; 数据持久性&#xff1a;通常情况下&#xff0c;容器运行起来之后&#xff0c;写入到其文件系统的文件暂时性的。当容器崩溃后&#xff0c;kubelet 将会重启该容器&#xff…

深度学习4. 循环神经网络 – Recurrent Neural Network | RNN

目录 循环神经网络 – Recurrent Neural Network | RNN 为什么需要 RNN &#xff1f;独特价值是什么&#xff1f; RNN 的基本原理 RNN 的优化算法 RNN 到 LSTM – 长短期记忆网络 从 LSTM 到 GRU RNN 的应用和使用场景 总结 百度百科维基百科 循环神经网络 – Recurre…