第 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.mzph.cn/news/60092.shtml

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

相关文章

C#将text文本中的单双行分开单独保存

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 文本的分割1.设定text文件的名称为02.文本导出 文本的分割 1.设定text文件的名称为0 代码如下&#xff1a; using System; using System.Collections.Generic; us…

读SQL学习指南(第3版)笔记06_连接和集合

1. 连接 1.1. 笛卡儿积 1.1.1. 交叉连接&#xff08;cross join&#xff09; 1.1.2. 查询并没有指定两个数据表应该如何连接&#xff0c;数据库服务器就生成了笛卡儿积 1.1.2.1. 两个数据表的所有排列组合 1.1.3. 很少会用到&#xff08;至少不会特意用到&#xff09; 1.…

layui框架学习(43:文件上传模块-下)

上一篇文章介绍文件上传模块使用示例时介绍了done和error事件&#xff0c;这两个事件是在文件上传成功&#xff08;原文&#xff1a;在上传接口请求完毕后触发&#xff0c;但文件不一定是上传成功的&#xff09;及上传失败&#xff08;原文&#xff1a;请求上传出现异常&#x…

深入浅出AXI协议(3)——握手过程

一、前言 在之前的文章中我们快速地浏览了一下AXI4协议中的接口信号&#xff0c;对此我们建议先有一个简单的认知&#xff0c;接下来在使用到的时候我们还会对各种信号进行一个详细的讲解&#xff0c;在这篇文章中我们将讲述AXI协议的握手协议。 二、握手协议概述 在前面的文章…

【运维】hadoop3.0.3集群安装(一)多节点安装

文章目录 一.Purpose二. Prerequisites三. Installation1. 节点规划2. Configuring Hadoop in Non-Secure Mode3. 准备工作4. 配置core-site.xmlhdfs-site.xmlyarn-site.xmlmapred-site.xmlworkers 4. 分发配置、创建文件夹5. 格式化6. 操作进程6.1. hdfs启动停止 6.2. yarn启动…

PyQt6 GUI界面设计和Nuitka包生成exe程序(全笔记)

PyQt6 GUI界面设计和Nuitka包,生成exe程序全笔记 目录一、PyQt6包安装1.1 进行环境配置和安装1.2 检查包是否安装成功。1.3 运行desinger.exe二、GUI界面设计,写程序,并能运行成功。三、Nuitka打包生成exe程序3.1 做Nuitka安装准备工作(1)安装C编译器,设置环境变量3.2 安…

新功能上线!Salesforce Field Service人工智能创新

Salesforce Field Service是Service Cloud的扩展&#xff0c;可提供员工管理的全面视图。Field Service专为进行现场服务的员工而设计&#xff0c;例如服务技术人员、服务座席、调度员等。随着Salesforce平台上线越来越多的生成式AI新增功能&#xff08;包括Sales Cloud、Marke…

浅谈红队资产信息收集经验

文章目录 子公司资产收集备案号|官网收集子域名|ip收集fofa灯塔ARLX情报社区 资产确认目录扫描Google Hacking绕过CDNnmap端口扫描参数技巧其他常用工具 子公司资产收集 红蓝对抗中往往只会给你目标企业的名称&#xff0c;以及对应的靶标系统地址&#xff0c;而很少有直接从靶标…

MySQL基础入门

推荐查看 数据库相关概念 MySQL百度百科 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的 RDBMS (Relational Databa…

KylinOS配置完静态IP地址后,保存按钮是灰色

问题: 配置完静态IP地址后,保存按钮置灰,并且提示“无效设置IPv4设置:ipv4.gateway:网关与”never-default”不兼容”。 原因: 这是由于禁止添加默认路由导致的。 解决方案: 1、使用nmcli命令: nmcli con modify "有线连接 1" ipv4.never-default no 执…

常见的数据结构之队列

一、介绍 队列(Queue)是一种常见的数据结构,用于存储和管理一系列数据元素,其中元素按照 先进先出(First-In-First-Out,简称FIFO)的原则进行插入和删除。 队列可以类比为现实生活中排队等候的场景,例如在超市收银台排队购物的顾客队列。 二、队列的基本操作 2.1 出…

Java代码审计15之Apache log4j2漏洞

文章目录 1、log4j简介2、复现2.1、高版本测试2.2、测试代码2.3、补充之dns探测2.3.1、rmi、ldap也可以dnslog探测 2.3.2、dnslog外带信息 3、漏洞原理3.1、漏洞的危害大的背景3.2、具体的代码调试 4、靶场测试4.1、dns探测4.2、工具下载与使用4.3、测试 5、bypass 1、log4j简介…

13、监测数据采集物联网应用开发步骤(9.2)

监测数据采集物联网应用开发步骤(9.1) TCP/IP Server开发 新建TCP/IP Server线程类com.zxy.tcp.ServerThread.py #! python3 # -*- coding: utf-8 -Created on 2017年05月10日 author: zxyong 13738196011 import socket,threading,time from com.zxy.tcp.TcpServer import …

CSA研讨会|聚焦云原生安全,探讨技术与应用策略

为产业数字化保驾护航&#xff0c; 云原生安全体系如何有效抵御网络威胁&#xff1f; 网络安全的下一个十年&#xff0c; 云原生安全是网络安全创新之路吗&#xff1f; CNAPP部署现状&#xff0c;你了解多少&#xff1f; 9月6日&#xff08;周三&#xff09;下午14&#xff1a…

推荐一本AI+医疗书:《机器学习和深度学习基础以及医学应用》,附21篇精选综述

当代医学仍然存在许多亟待解决的问题&#xff0c;比如日益增加的成本、医疗服务水平的下降...但近几年AI技术的发展却给医疗领域带来了革命性的变化&#xff0c;因此AI医疗迅速兴起。 从目前已知的成果来看&#xff0c;人工智能在医学领域的应用已经相当广泛&#xff0c;智能诊…

创建python环境——Anaconda

在Windows中安装Anaconda和简单使用 一.Anaconda发行概述 Anaconda是一个可以便捷获取和管理包&#xff0c;同时对环境进行统一管理的发行版本&#xff0c;它包含了conda、 Python在内的超过180个科学包及其依赖项。 1.Anaconda发行版本具有以下特点&#xff1a; (1)包含了…

统一使用某一个包管理工具,比如yarn pnpm

原因&#xff1a;前端每个人的习性不一样&#xff0c;有人用npm 有人用yarn等包管理工具&#xff0c;混合下载插件容易出bug&#xff0c;就用个小工具锁住就行了&#xff0c;只能使用yarn或者pnpm反向下载依赖和下载插件。不然就报错 1.在项目主目录下创建preinstall.js // 如…

Linux命令查看CPU、内存、IO使用情况简单介绍

文章目录 1. CPU相关介绍1.1 物理CPU1.2 物理CPU内核1.3 逻辑CPU1.4 几核几线程1.5 CPU设计图 2. top 查看系统负载、CPU使用情况2.1 系统整体的统计信息2.2 进程信息2.3 top命令使用 3. lscpu 显示有关 CPU 架构的信息4. free 查看内存信息5. iostat 查看io信息 1. CPU相关介绍…