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

news2024/11/29 20:46:14

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>

/*  定义墙元素值为 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.coloradmin.cn/o/951645.html

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

相关文章

基于Googlenet深度学习网络的人脸身份识别matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ..................................................................... % 定义修改的范围 …

IP子网的划分

文章目录 一、子网掩码1. 产生背景2. 定义3. 分类 二、VLSM算法1. 得出下列参数2. 计算划分结果3. 举例子计算 三、常见子网划分对应关系四、练习IP编址题目需求解题1. 192.168.1.100/282. 172.16.0.58/263. 25.83.149.222/254. 100.100.243.18/205. 10.100.100.100/10 首先可以…

Python Qt学习(一)一个简单的JSON数据预览界面

先贴上代码&#xff1a; # -*- coding: utf-8 -*-# Form implementation generated from reading ui file json_converter.ui # # Created by: PyQt5 UI code generator 5.15.9 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. …

Python飞机大战小游戏

游戏规则&#xff1a;键盘上下左右键控制飞机移动 游戏展示图片&#xff1a; 源码&#xff1a; 第一个py命名为&#xff1a;plane_main.py import pygamefrom plane_sprites import *class PlaneGame(object):# """飞机大战主游戏"""def __in…

ExpressLRS开源之基本调试数据含义

ExpressLRS开源之基本调试数据含义 1. 源由2. 代码2.1 debugRcvrLinkstats2.2 debugRcvrSignalStats 3. 含义解释3.1 ID(packetCounter),Antenna,RSSI(dBm),LQ,SNR,PWR,FHSS,TimingOffset3.2 IRQ_CNT,RSSI_AVE,SNR_AVE,SNV_MAX,TELEM_CNT,FAIL_CNT 4. 总结5. 参考资料 1. 源由 …

详解 ElasticSearch Kibana 配置部署

默认安装部署所在机器允许外网 SSH工具 Putty 链接&#xff1a;https://pan.baidu.com/s/1b6gumtsjL_L64rEsOdhd4A 提取码&#xff1a;lxs9 Winscp 链接&#xff1a;https://pan.baidu.com/s/1tD8_2knvv0EJ5OYvXP6VTg 提取码&#xff1a;lxs9 WinSCP安装直接下一步到完成…

UE 5 GAS 在项目中通过数据初始化

近期&#xff0c;在制作多角色&#xff0c;考虑到角色和角色之间有很多共用的内容&#xff0c;正常项目中的实现的话&#xff0c;会通过数据的方式去实现角色初始化&#xff0c;接下来介绍一下&#xff0c;我的实现方式。 以上是我设置的相应的数据&#xff0c;上面最简单的名…

设计模式行为模式-命令模式

文章目录 前言定义结构工作原理优点适用场景消息队列模式Demo实现分写业务总结 前言 定义 命令模式&#xff08;Command Pattern&#xff09;是一种行为型设计模式&#xff0c;用于将请求封装为对象&#xff0c;从而使你可以使用不同的请求、队列或者日志请求来参数化其他对象…

服务器端污染属性反射提升权限

污染属性反射检测服务器端原型污染 通过服务器端原型污染提升权限 Lab: Privilege escalation via server-side prototype pollution 必要知识点 开发人员很容易陷入的一个陷阱是忘记或忽略 JavaScript 循环迭代对象的所有可枚举属性这一事实&#xff0c;包括它通过原型链继…

医学案例|线性回归

一、案例介绍 某医师预研究糖尿病患者的总胆固醇和甘油三酯对空腹血糖的影响&#xff0c;某研究者调查40名糖尿病患者的总胆固醇、甘油三酯和空腹血糖的测量值如下&#xff0c;试根据上述研究问题作统计分析。 二、问题分析 本案例想要研究一些变量&#xff08;总胆固醇和甘油…

PocketMiner:基于深度学习发现蛋白的隐式口袋

文章目录 1. 文章简介2. 前言3. 方法3.1 模型框架 4. 结果4.1 已知隐式口袋在分子动力学模拟分析迅速打开4.2 图神经网络模型能够准确预测模拟中口袋的动态变化4.3 隐式口袋数据集数据集揭示了新的隐式口袋形成的模式4.4 PocketMiner能够从无配体的蛋白结构中精准预测预测口袋4…

2007-2022年上市公司污染排放数据/2007-2022年上市公司污染排放水平、污染排放量数据

2007-2022年上市公司污染排放数据/2007-2022年上市公司污染排放水平、污染排放量数据 1、时间&#xff1a;2007-2022年 2、指标&#xff1a;证券代码、year、化学需氧量、氨氮排放量、总氮、总磷、水体综合污染当量对数、二氧化硫、氮氧化物、烟尘、空气综合污染当量对数、总…

小游戏分发平台如何以技术拓流?

2023年&#xff0c;小游戏的发展将受到多方面的影响&#xff0c;例如新技术的引入、参与小游戏的新玩家以及游戏市场的激烈竞争等。首先&#xff0c;新技术如虚拟现实&#xff08;VR&#xff09;、增强现实&#xff08;AR&#xff09;和机器人技术都可以带来新颖的游戏体验。其…

滑动窗口实例1(长度最小的子数组)

题目&#xff1a; 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 示例 1&#xff1a; …

VC++使用Microsoft Speech SDK进行文字TTS朗读

Microsoft Speech SDK下载地址 https://www.microsoft.com/en-us/download/details.aspx?id=10121 需要msttss22L.exe、SpeechSDK51.exe、SpeechSDK51LangPack.exe三个,下载后全部安装 使用VS2005建立一个win32控制台项目 朗读"hello word"、中文“你好”的程序 …

百科有不需要的信息怎么删除?

百科词条的权威性众所周知&#xff0c;所以百度百科的内容审核也非常严格&#xff0c;百科营销成为目前网络营销工作中一个难点&#xff0c;很多企业无法得到自己完全满意的百度百科词条 &#xff0c;这其实也是合理的。小马识途营销顾问分析&#xff0c;百科词条内容是提供给广…

10、【WebGIS实战】图层篇——通用服务图层加载全流程(适用于全部图层)

大家好,我是X北辰北。本文是「WebGIS实战」系列,关注这个标签,阅读所有文章,成为WebGIS开发高手。 图层可以理解为添加到地图上面的数据,比如我们要在地图上展示成都市所有大型公园的位置,那么当前地图中除了初始化地图时添加的底图之外,在底图的上面我们还叠加了一份关…

HuggingFace中的 Files and versions 如何优雅下载到本地?(Python requests,tqdm)

前言 在使用huggingface把玩各种大模型时&#xff0c;如果选择从远程加载模型&#xff0c;这个过程可能因为网络问题而非常耗时甚至直接失败&#xff0c;所以把模型、分词器等相关文件下载到本地&#xff0c;再直接从本地加载就成了不可回避的流程。 在进入具体版本的模型后&…

新版Mongodb(6.0以上)找不到mongo.exe

安装目录下/bin目录中&#xff0c;没有mongo.exe文件&#xff0c;只有mongod和mongos&#xff0c;以及一个powershell命令脚本。 原因在于&#xff0c;mongodb6.0以后做出了重大改变&#xff0c;mongodb已经不再默认为你安装shell工具&#xff0c;因此需要安装一个额外的shell…

二十二、迭代器模式

一、什么是迭代器模式 迭代器&#xff08;Iterator&#xff09;模式的定义&#xff1a;迭代器模式是一种对象行为型模式&#xff0c;它提供一个对象来顺序访问聚合对象中的一系列数据&#xff0c;而不暴露聚合对象的内部表示。   迭代器模式包含以下主要角色: 抽象聚合&…