第 3 章 栈和队列(顺序栈,算法 3.3,使用栈解答迷宫问题)

news2025/1/18 6:28:30

1. 背景说明

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

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

迷宫示意图:

    输入文本:

10 10

18

1 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 1

1 1

8 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>
#include <Windows.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;
}

/* 设置字体颜色,入参为 0 - 15 */
static void SetColor(const unsigned short textColor)
{
	if ((textColor >= 0) && (textColor <= 15)) {
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), textColor);
	} else {
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
	}
}

/* 如果存在路径,输出求得的迷宫的解 */
void PrintMazePath(int row, int col, MazeType* maze)
{
	for (int i = 0; i < row; ++i) {
		for (int j = 0; j < col; ++j) {
			if ((*maze)[i][j] > 0) {
				SetColor(2);
				printf("%3d", (*maze)[i][j]);
			} else {
				SetColor(7);
				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.coloradmin.cn/o/967482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Auto DevOps介绍

1 Preface/Foreword 随着国际化&#xff0c;信息化&#xff0c;当今是一个VUCA时代。 VUCA&#xff1a;Volatile &#xff08;易变的&#xff09;&#xff0c;Uncertain &#xff08;不确定的&#xff09;&#xff0c;Complicated &#xff08;复杂的&#xff09;&#xff0c…

类ChatGPT大模型LLaMA及其微调模型

1.LLaMA LLaMA的模型架构:RMSNorm/SwiGLU/RoPE/Transfor mer/1-1.4T tokens 1.1对transformer子层的输入归一化 对每个transformer子层的输入使用RMSNorm进行归一化&#xff0c;计算如下&#xff1a; 1.2使用SwiGLU替换ReLU 【Relu激活函数】Relu(x) max(0,x) 。 【GLU激…

nginx-反向代理缓存

反向代理缓存相当于自动化动静分离。 将上游服务器的资源缓存到nginx本地&#xff0c;当下次再有相同的资源请求时&#xff0c;直接讲nginx缓存的资源返回给客户端。 本地缓存资源有一个过期时间&#xff0c;当超过过期时间&#xff0c;则重新向上游服务器重新请求获取资源。…

书籍推荐-1 Python编程:从入门到实践(第2版)

Python编程&#xff1a;从入门到实践&#xff08;第2版&#xff09; 书籍背景 作者介绍 埃里克马瑟斯&#xff08;Eric Matthes&#xff09;&#xff0c;高中科学和数学老师&#xff0c;现居住在美国阿拉斯加&#xff0c;在当地讲授Python入门课程。他从5岁开始就一直在编写程序…

mysql:[Some non-transactional changed tables couldn‘t be rolled back]不支持事务

1. mysql创建表时默认引擎MyIsam&#xff0c;因此不支持事务的操作&#xff1b; 2. 修改mysql的默认引擎&#xff0c;可以使用show engine命令查看支持的引擎&#xff1a; 【my.conf详情说明】my.cnf配置文件注释详解_xiaolin01999的博客-CSDN博客 3. 原来使用MyIsam创建的表…

python: excel 换行符(_x000D_)

data4 dataframe1.loc[4:34] for idx, datavalue in data4.iterrows():#strnumCommon.Utils.Utils.getAnnualLeave(data)print("[{}]: {}".format(idx, datavalue))slistdatavalue.tolist()hbllBLL.EmpLoyeeHolidaysGet.EmpLoyeeHolidaysGet() #病假4小時_x000D_事假…

无人机集群路径规划MATLAB:孔雀优化算法POA求解无人机集群三维路径规划

一、无人机模型简介 单个无人机三维路径规划问题及其建模_IT猿手的博客-CSDN博客 二、孔雀优化算法POA介绍 孔雀优化算法( Peafowl Optimization Algorithm, POA), 是由 Jingbo Wang 等于2022 年提出的一种群体智能优化算法。其灵感来源于孔雀的群体行为。 智能优化算法&am…

PlantUML入门教程:画时序图

软件工程中会用到各种UML图&#xff0c;例如用例图、时序图等。那我们能不能像写代码一样去画图呢&#xff1f; 今天推荐一款软件工程师的作图利器--PlantUML&#xff0c;它能让你用写代码的方式快速画出UML图。 一、什么是PlantUML&#xff1f; PlantUML是一个允许你快速作出…

移动零00

题目链接 移动零 题目描述 注意点 将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序必须在不复制数组的情况下原地对数组进行操作 解答思路 采用双指针的思路&#xff0c;左指针指向已移动零的数组的尾部&#xff0c;右指针指向为移动零的数组的头部&…

深度学习推荐系统(五)DeepCrossing模型及其在Criteo数据集上的应用

深度学习推荐系统(五)Deep&Crossing模型及其在Criteo数据集上的应用 在2016年&#xff0c; 随着微软的Deep Crossing&#xff0c; 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出&#xff0c; 推荐系统全面进入了深度学习时代&#xff0c; 时至今日&am…

Python实现字符串模糊匹配

在一个字符串中&#xff0c;有时需对其中某些内容进行模糊匹配以实现条件的判定&#xff0c;如在“你好&#xff0c;hello,world”中判断是否含有“llo”。Python中通过re.search()方法实现&#xff0c;特别地&#xff0c;对于首位起始的内容匹配&#xff0c;也可通过re.match(…

Apolo学习

安装&#xff08;java1.8 mysql 5.6.5以上&#xff09; 下载quickStart的包&#xff0c;早apollo下执行两个sql。如果不执行这两个sql&#xff0c;apollo是执行不起来的。会有两个表来记录apollo的执行情况。其中一个表叫apolloportaldb 在apollo目录下会有执行的包。.sh是…

stm32f1xx单片机拦截中断源代码

这个是实现后的效果&#xff0c;可以看到已经没有中断的效果了 这个是拦截前的效果可以看到电平是在变化的 实现原理非常简单&#xff1a;一句话搞定&#xff1a; if(TIM2->CNTTIM2->ARR-5)TIM2->CNT-5; 以下是完整的代码&#xff1a;是用来补充说明和筹字数的 /* …

山西电力市场日前价格预测【2023-09-04】

日前价格预测 预测明日&#xff08;2023-09-04&#xff09;山西电力市场全天平均日前电价为305.57元/MWh。其中&#xff0c;最高日前电价为349.83元/MWh&#xff0c;预计出现在19: 15。最低日前电价为226.28元/MWh&#xff0c;预计出现在13: 30。 价差方向预测 1&#xff1a; 实…

Linux CentOS7 系统中添加用户

在linux centOS7系统中&#xff0c;添加用户是管理员的基本操作。作为学习linux系统的基本操作&#xff0c;对添加用户应该多方面了解。 添加用户的命令useradd&#xff0c;跟上用户名&#xff0c;就可以快速创建一个用户。添加一些选项&#xff0c;可以设置更人性化的用户信息…

并发下的Map常见面试题

HashMap 和 HashTable 有什么区别&#xff1f;java中的另一个线程安全的与HashMap极其类似的类是什么&#xff1f;同样是线程安全&#xff0c;它与HashTable在线程同步上有什么不同&#xff1f;HashMap 与 ConcurrentHashMap的区别&#xff1f;为什么 ConcurrentHashMap 比 Has…

【Python技巧】快速安装各种常用库pip、whl、tar.gz最新最全安装方法(超时、快速安装))

【Python技巧】安装各种常用库pip、whl、tar.gz最新最全安装方法 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&…

Linux系统调试中出现核心转储(core dump)的问题

​ 大家好&#xff0c;我是ST。今天主要分享一下&#xff0c;Linux应用程序发生Segmentation fault段错误时&#xff0c;如何利用core dump文件定位错误。 核心转储 在 Linux 系统中&#xff0c;常将“主内存”称为核心(core)&#xff0c;而核心映像(core image) 就是 “进…

Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录

Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录 目录 Stable Diffuse 之 本地环境部署/安装包下载搭建过程简单记录 一、简单介绍 二、注意事项 三、环境搭建 git 下载和安装 python 下载和安装 stable-diffusion-webui 下载和安装 测试 stable diffuse w…