C数据结构与算法——队列 应用(C语言纯享版 迷宫)

实验任务

(1) 掌握顺序循环队列及其C语言的表示;
(2) 掌握入队、出队等基本算法的实现;
(3) 掌握顺序循环队列的基本应用(求解迷宫通路)。

实验内容

  • 使用C语言实现顺序循环队列的类型定义与算法函数;
  • 编写main()函数并根据需要修改、补充相关的类型定义与函数,以实现“求解迷宫通路”问题:
  • 求解迷宫通路问题描述:
    • 给定一个M×N的迷宫图,指定一个入口与一个出口;
    • 规定行走规则为:按“上右下左”优先顺序向相邻空位移动1格,用(i,j)表示迷宫中的第i行第j列的一个方块
    • 在迷宫外围加上围墙;
  • 实现指定入口和出口的固定迷宫;
  • 实现随机入口和出口的固定迷宫;
  • 实现障碍、入口和出口都随机的迷宫。

实验源码

注意:必须在Dos窗口下运行,并且以管理员身份打开Dos窗口最佳

#include <stdio.h>
#include <time.h>
#include "windows.h"#define MAXSIZE 1000
#define ROW 15
#define LINE 15
#define RATIO 0.6875 // 44/64的比例
#define COORDINATE -1 // 坐标默认 值
#define DISTOP 5 // 迷宫距离顶端距离格数#define PASS 0 // 通路
#define WALL 1 // 墙
#define ENTRY 2 // 入口
#define EXIT 3 // 出口
#define DEAD 5 // 死路// 延时设置
int walkDelay = 500;
int dirDelay = 1000;typedef struct Box {int x;           // 点的横坐标(行)int y;           // 点的纵坐标(列)int pre;         // 上一个点的下标
} Box;typedef struct {Box *base;int front;int rear;
} SqQueue;void Map(int map[][LINE]); // 生成地图void KnuthShuffle(int map[], int length); // 洗牌算法void swapInt(int *a, int *b); // 辅助洗牌算法 交换void PrintMap(int map[][LINE]); // 打印迷宫地图boolean InitQueue(SqQueue *queue); // 循环队列的初始化void Walk(SqQueue *queue, int in_x, int in_y, int map[][LINE]); // 移动迷宫boolean EnQueue(SqQueue *queue, Box node); // 循环队列入队列boolean IsFull(SqQueue *queue); // 判队满boolean IsEmpty(SqQueue *queue); // 判队空Box DeQueue(SqQueue *queue); // 循环队列出队列void ShowPath(SqQueue *queue, int end); // 求解最短路径void Color(short x); // 自定义函根据参数改变颜色void DirTest(int map[][LINE], int dir, int j, int k); // 方向试探void DeadPath(int j, int k); // 置为死路void GotoXY(int x, int y); // 将光标移至屏幕 第x列,第y行 处void DisplayQueue(SqQueue *queue); // 队列动态展示void HideCursor(void); // 隐藏光标/*** <h2>顺序队列实验</h2>* <h3>随机迷宫问题</h3>* <h3>注意:请在Dos窗口下运行</h3>* <h4>非循环队列,并不是真的退出队列</h4>* @return 0*/
int main() {GotoXY(0, 0);Color(9);printf("  使用队列解决迷宫通路问题 \n");GotoXY(0, 1);printf("==============================\n");GotoXY(0, 2);Color(12);printf("X--走过的无效通路");Color(9);printf("  囚--起点\n");GotoXY(0, 3);Color(13);printf("O--走过的有效通路");Color(11);printf("  口--终点\n");GotoXY(0, 4);printf("------------------------------\n");srand(time(NULL));int map[ROW][LINE];Map(map);PrintMap(map);SqQueue queue;if (!(InitQueue(&queue))) {printf("队列初始化失败~~\n");return 0;}int in_x, in_y;for (int i = 0; i < ROW; i++) {for (int j = 0; j < LINE; j++) {if (map[i][j] == ENTRY) {in_x = i;in_y = j;}}}HideCursor();DisplayQueue(&queue);Walk(&queue, in_x, in_y, map);getchar();
}void Map(int map[][LINE]) {int length = (ROW - 2) * (LINE - 2); // 8 * 8 内区域int randArr[length];for (int i = 0; i < length; i++) {if (i == 0) {randArr[i++] = ENTRY;randArr[i++] = EXIT;}if (i < (length * RATIO) + 2) {randArr[i] = PASS;} else {randArr[i] = WALL;}}KnuthShuffle(randArr, length); // 打乱 内区域// 赋值整张地图for (int i = 0; i < ROW; i++) {for (int j = 0; j < LINE; j++) {// 这里一个小技巧:只要前面四个表达式一个为假,说明未到边界赋值,保证Length不会越界if (i != 0 && i != ROW - 1 && j != 0 && j != LINE - 1 && length--) {map[i][j] = randArr[length];} else {map[i][j] = WALL;}}}
}void KnuthShuffle(int map[], int length) {for (int i = length - 1; i >= 1; i--) {swapInt(&map[i], &map[rand() % (i + 1)]);}
}void swapInt(int *a, int *b) {int t;t = *a;*a = *b;*b = t;
}void PrintMap(int map[][LINE]) {for (int i = 0; i < ROW; i++) {for (int j = 0; j < LINE; j++) {GotoXY(j * 2, i + DISTOP);switch (map[i][j]) {case PASS:printf(" ");break;case WALL:Color(10);printf("围");break;case ENTRY:Color(9);printf("囚");break;case EXIT:Color(11);printf("口");break;}}printf("\n");}Sleep(3000);
}boolean InitQueue(SqQueue *queue) {queue->base = (Box *) malloc(sizeof(Box) * MAXSIZE);if (!(queue->base)) {return FALSE;}queue->front = queue->rear = 0;return TRUE;
}void Walk(SqQueue *queue, int in_x, int in_y, int map[][LINE]) {// 起点先入队列Box node; // 生成当前位置(起点)node.x = in_x;node.y = in_y;node.pre = COORDINATE; // 起点位置下标 -1EnQueue(queue, node); // 起点入队列while (!(IsEmpty(queue))) { // 无路可走的情况,回到起点node = DeQueue(queue); // 取出队头位置 队头指针front++if (map[node.x][node.y] == EXIT) { // 判断当前位置是否是终点ShowPath(queue, queue->front);return;}int dir; // 装方向Box tNode; // 生成下一个位置for (dir = 0; dir < 4; dir++) { // 判断当前位置各个方向是否可走switch (dir) {case 0:tNode.x = node.x - 1;tNode.y = node.y;DirTest(map, dir, node.x, node.y);break;case 1:tNode.x = node.x;tNode.y = node.y + 1;DirTest(map, dir, node.x, node.y);break;case 2:tNode.x = node.x + 1;tNode.y = node.y;DirTest(map, dir, node.x, node.y);break;case 3:tNode.x = node.x;tNode.y = node.y - 1;DirTest(map, dir, node.x, node.y);break;}if (map[tNode.x][tNode.y] == PASS || map[tNode.x][tNode.y] == EXIT) { // 判断这个方向 是否可走tNode.pre = queue->front - 1; // 把节点位置的下标给 新位置EnQueue(queue, tNode); // 入队if (map[tNode.x][tNode.y] == PASS) {map[tNode.x][tNode.y] = DEAD;DeadPath(tNode.x, tNode.y);}}}}// 这里加二号条件的原因是:此程序使用的是终点出队列即停止,但是也不排除 到终点即为空if (IsEmpty(queue) && map[node.x][node.y] != EXIT) {GotoXY(0, ROW + DISTOP + 2);Color(12);printf("\t无路可走,死翘翘了~~\n");}
}boolean EnQueue(SqQueue *queue, Box node) {if (IsFull(queue)) {return FALSE;}queue->base[queue->rear] = node; // 新元素插入队尾queue->rear = queue->rear + 1; // 队尾指针加 1DisplayQueue(queue);return TRUE;
}boolean IsFull(SqQueue *queue) {return queue->rear + 1 == queue->front; // 非循环队列
}boolean IsEmpty(SqQueue *queue) {return queue->rear == queue->front;
}Box DeQueue(SqQueue *queue) {Box box = queue->base[queue->front++];DisplayQueue(queue);return box; // 取出队头元素,并把其出队列
}void ShowPath(SqQueue *queue, int end) {int i, tmp;for (i = end - 1; i >= 0;) {tmp = queue->base[i].pre;queue->base[i].pre = COORDINATE;i = tmp;}int count = 0, ti;for (i = 1; i < end; i++) { // i = 1, 保证不是终点即可if (queue->base[i].pre == COORDINATE) {if (count == 0) {GotoXY(LINE * 2 + 35, DISTOP - 1);printf("↓ 路径打印 ↓");GotoXY(LINE * 2 + 35, DISTOP);printf("|__i__j__pre__|");}count++;GotoXY(LINE * 2 + 35, DISTOP + count);printf("|_____________|\n");Color(11);GotoXY(LINE * 2 + 35 + 3, DISTOP + count);printf("%d", queue->base[i].x);GotoXY(LINE * 2 + 35 + 7, DISTOP + count);printf("%d", queue->base[i].y);GotoXY(LINE * 2 + 35 + 10, DISTOP + count);printf("%d", queue->base[i].pre);if (count == 1) {ti = i;continue;}GotoXY(queue->base[ti].y * 2, queue->base[ti].x + DISTOP);Color(15);if (queue->base[i].x - queue->base[ti].x == -1 &&queue->base[i].y - queue->base[ti].y == 0) {printf("↑");} else if (queue->base[i].x - queue->base[ti].x == 0 &&queue->base[i].y - queue->base[ti].y == 1) {printf("→");} else if (queue->base[i].x - queue->base[ti].x == 1 &&queue->base[i].y - queue->base[ti].y == 0) {printf("↓");} else {printf("←");}ti = i;}}
}void Color(short x) {if (x >= 0 && x <= 15) { // 参数在0-15的范围颜色SetConsoleTextAttribute( // 调用设置控制台文本属性函数(调用获取句柄函数(不理解), 不理解)GetStdHandle(STD_OUTPUT_HANDLE), x);    // 只有一个参数,改变字体颜色} else { // 默认的颜色白色SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);}
}void DirTest(int map[][LINE], int dir, int j, int k) {GotoXY(k * 2, j + DISTOP);Color(15);switch (dir) {case 0:printf("↑");break;case 1:printf("→");break;case 2:printf("↓");break;case 3:printf("←");break;}Sleep(dirDelay);GotoXY(k * 2, j + DISTOP);Color(13);switch (map[j][k]) {case ENTRY:Color(9);printf("囚");break;case DEAD:Color(12);printf("X");break;}
}void DeadPath(int j, int k) {GotoXY(k * 2, j + DISTOP);Color(12);printf("X");Sleep(walkDelay);
}void GotoXY(int x, int y) {COORD pos = {x, y}; // 坐标HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取句柄(标准输出句柄)SetConsoleCursorPosition(hOut, pos); // 设置控制台光标位置
}void DisplayQueue(SqQueue *queue) {int len = ROW - 1;Color(12);GotoXY(LINE * 2 + 10, DISTOP);printf("|__i__j__di__| <- top");for (int j = 1; j <= len; j++) {GotoXY(LINE * 2 + 10, DISTOP + j);printf("|____________|\n");}int length = queue->rear;for (int i = 0; i < length; i++, len--) {if (len == 0) {len = ROW - 1;for (int j = 1; j <= len; j++) {GotoXY(LINE * 2 + 10, DISTOP + j);printf("|____________|\n");}}Color(11);GotoXY(LINE * 2 + 10 + 3, DISTOP + len);printf("%d", queue->base[i].x);GotoXY(LINE * 2 + 10 + 7, DISTOP + len);printf("%d", queue->base[i].y);GotoXY(LINE * 2 + 10 + 10, DISTOP + len);printf("%d", queue->base[i].pre);}
}void HideCursor(void) {CONSOLE_CURSOR_INFO cursor_info = {1, 0};SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

实验结果

在这里插入图片描述

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

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

相关文章

算法与数据结构(三)--栈

一.栈的基本概念 栈是一种特殊的表&#xff0c;这种表只在表首进行插入和删除操作。 因此&#xff0c;表首对于栈来说具有特殊的意义&#xff0c;称为栈顶。相应的&#xff0c;表尾称为栈底。不含任何元素的栈称为空栈。 栈的修改遵循后进先出的原则&#xff0c;Last In First…

Zabbix邮件报警(163网易邮箱)

目录 一、电脑登录网易邮箱配置 二、Server端安装配置邮件服务器 邮箱查看 三、编辑zabbix_server.conf 引用邮件脚本 查看邮件 五、配置zabbix web监控项邮件报警 操作思路 Server.zabbix.com web操作 确认报警媒介信息 配置zabbix中的用户所使用的报警媒介类型以及接收邮…

【网络】HTTPS协议

目录 一、概念 1、HTTPS 2、加密解密 3、加密的必要性 4、常见的加密方式 4.1、对称加密 4.2、非对称加密 5、数据摘要 && 数据指纹 6、数字签名 二、HTTPS的工作过程 1、只使用对称加密 2、只使用非对称加密 3、双方都使用非对称加密 4、非对称加密 对…

rust gtk 桌面应用 demo

《精通Rust》里介绍了 GTK框架的开发&#xff0c;这篇博客记录并扩展一下。rust 可以用于桌面应用开发&#xff0c;我还挺惊讶的&#xff0c;大学的时候也有学习过 VC&#xff0c;对桌面编程一直都很感兴趣&#xff0c;而且一直有一种妄念&#xff0c;总觉得自己能开发一款很好…

深入学习 Redis - 深挖经典数据类型之 set

目录 前言 一、Set 类型 1.1、操作命令 sadd / smembers&#xff08;添加&#xff09; sismember&#xff08;判断存在&#xff09; scard&#xff08;获取元素个数&#xff09; spop&#xff08;删除元素&#xff09; smove&#xff08;移动&#xff09; srem&#x…

Golang time 包以及日期函数

time 包 在 golang 中 time 包提供了时间的显示和测量用的函数。 time.Now()获取当前时间 可以通过 time.Now()函数获取当前的时间对象&#xff0c;然后获取时间对象的年月日时分秒等信息。 示例代码如下&#xff1a; package mainimport ("fmt""time" )…

Redis原理篇(二)

Redis原理 Redis数据结构 Redis网络模型 RESP协议 Redis内存回收 Redis原理篇 一、原理篇-Redis数据结构 1.1 Redis数据结构-动态字符串 我们都知道Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不…

网络安全 Day19-计算机网络基础知识04(网络协议)

计算机网络基础知识04&#xff08;网络协议&#xff09; 1. ARP1.1 ARP通讯原理1.2 arp欺骗1.3 ARP欺骗与预防1.4 排查ARP病毒 2. DHCP工作原理&#xff08;自动分配内网IP&#xff09;3. TCP协议三次握手、四次挥手原理4. DNS协议工作原理 1. ARP Linux查看arp&#xff1a;ar…

聊聊STM32 ADC的话题

STM32 微控制器系列提供了多个模拟数字转换器&#xff08;ADC&#xff09;模块&#xff0c;用于实现模拟信号的采集和转换为数字信号。ADC 在很多应用中都是非常重要的&#xff0c;例如传感器数据采集、电压测量等。 在 STM32 中&#xff0c;ADC 可以通过 STM32HAL 库提供的函…

自动驾驶感知系统-超声波雷达

超声波雷达&#xff0c;是通过发射并接收40kHz的超声波&#xff0c;根据时间差算出障碍物距离。其测距精度是1~3cm.常见的超声波雷达有两种&#xff1a;第一种是安装在汽车前后保险杠上的&#xff0c;用于测量汽车前后障碍物的驻车雷达或倒车雷达&#xff0c;称为超声波驻车辅助…

时间复杂度和空间复杂度

在计算机科学中&#xff0c;算法的效率是一个重要的概念。算法的效率可以通过复杂度来度量&#xff0c;其中包括时间复杂度和空间复杂度。 了解算法的复杂度对于程序员来说非常重要。在解决实际问题时&#xff0c;我们需要选择合适的算法来保证程序的性能和效率。因此&#xff…

【前端笔记】本地运行cli项目报错ERR_OSSL_EVP_UNSUPPORTED

报错原因 Node版本>17.x&#xff0c;本地npm run 起项目后会发现终端报错&#xff0c;具体有以下2块关键信息&#xff1a; Error: error:0308010C:digital envelope routines::unsupported和 opensslErrorStack: [ error:03000086:digital envelope routines::initializa…

SpringCloud学习路线(9)——服务异步通讯RabbitMQ

一、初见MQ &#xff08;一&#xff09;什么是MQ&#xff1f; MQ&#xff08;MessageQueue&#xff09;&#xff0c;意思是消息队列&#xff0c;也就是事件驱动架构中的Broker。 &#xff08;二&#xff09;同步调用 1、概念&#xff1a; 同步调用是指&#xff0c;某一服务…

ProtoBuf入门概念

目录&#xff1a; 序列化概念ProtoBuf是什么ProtoBuf的使⽤特点安装ProtoBuf如何学习ProtoBuf 1.序列化概念 序列化和反序列化 序列化&#xff1a;把对象转换为字节序列的过程称为对象的序列化。反序列化&#xff1a;把字节序列恢复为对象的过程称为对象的反序列化。 什么…

【搜索引擎Solr】Apache Solr 神经搜索

Sease[1] 与 Alessandro Benedetti&#xff08;Apache Lucene/Solr PMC 成员和提交者&#xff09;和 Elia Porciani&#xff08;Sease 研发软件工程师&#xff09;共同为开源社区贡献了 Apache Solr 中神经搜索的第一个里程碑。 它依赖于 Apache Lucene 实现 [2] 进行 K-最近邻…

【Python笔记】Python + xlrd + pymysql读取excel文件数据并且将数据插入到MySQL数据库里面

这篇文章&#xff0c;主要介绍Python xlrd pymysql读取excel文件数据并且将数据插入到MySQL数据库里面。 目录 一、Python读取excel 1.1、安装xlrd库 1.2、打开excel工作簿 1.3、获取sheet工作表 1.4、操作row数据行 1.5、操作column数据列 1.6、操作单元格 二、读取…

Bean 作用域和生命周期

1.通过⼀个案例来看 Bean 作⽤域的问题 假设现在有⼀个公共的 Bean&#xff0c;提供给 A ⽤户和 B ⽤户使⽤&#xff0c;然⽽在使⽤的途中 A ⽤户却“悄悄”地修 改了公共 Bean 的数据&#xff0c;导致 B ⽤户在使⽤时发⽣了预期之外的逻辑错误。 1.1 被修改的 Bean 案例 公…

openfeign调用文件服务的文件上传接口报错:Current request is not a multipart request

解决办法&#xff1a; Api 接口 Api(tags "文件上接口") RestController public class FileController {Autowiredprivate FileFeignService fileFeignService;ApiOperation("上传文件")PostMapping(value "/uploadFile")public ResData<…

入门前端监控

背景 前端监控是指通过一系列手段对Web页面或应用程序进行实时监控和数据采集&#xff0c;以了解页面或应用程序的性能状况、用户行为等等&#xff0c;并及时发现和解决潜在的问题。一个完整的前端监控平台可以包括&#xff1a;数据收集与上报、数据整理与存储、数据展示这里仅…

Java连锁门诊医院HIS信息管理系统源码

Java连锁门诊医院HIS信息管理系统源码&#xff1a;SaaS运维平台多医院多机构多门诊入驻强大的电子病历完整开发文档 一、系统概述 ❉采用主流成熟技术&#xff0c;软件结构简洁、代码规范易阅读&#xff0c;SaaS应用&#xff0c;全浏览器访问前后端分离&#xff0c;多服务协同…