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

news2024/10/11 2:21:10

实验任务

(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; // 起点位置下标 -1

    EnQueue(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; // 队尾指针加 1
    DisplayQueue(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.coloradmin.cn/o/790025.html

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

相关文章

架构设计-高性能(一、存储高性能)

1.简介 数据存储的性能是系统高性能的两大组成部分之一。目前市场的数据存储技术是五花八门&#xff0c;并且目前针对在大数据环境下针对不同的需求和场景提出了更多不同类型的数据库。本文主要讲解分类中的关系型数据库和NoSql数据库的高性能。 2.关系型数据库 虽然存储技术在…

ClickHouse(二):ClickHouse特性

​目录 1. 完备的DBMS功能 2. 列式存储 3. 数据压缩 4. 向量化执行引擎 5. 关系模型与标准SQL查询 ​​​​​​​6. 多样化的表引擎 ​​​​​​​7. 多线程与分布式 ​​​​​​​8. 多主架构 ​​​​​​​9. 交互式查询 ​​​​​​​10. 数据分片与分布式查询…

03 shell 编程

变量 语言型 编译型语言 解释型语言 shell脚本语言是解释型语言shell脚本的本质&#xff1a;shell命令的有序集合 shell 编程的基本过程 基本过程分为三步&#xff1a; step1. 建立 shell 文件 包含任意多行操作系统命令或shell命令的文本文件; step2. 赋予shell文件执行…

Flutter 状态组件 InheritedWidget

Flutter 状态组件 InheritedWidget 视频 前言 今天会讲下 inheritedWidget 组件&#xff0c;InheritedWidget 是 Flutter 中非常重要和强大的一种 Widget&#xff0c;它可以使 Widget 树中的祖先 Widget 共享数据给它们的后代 Widget&#xff0c;从而简化了状态管理和数据传递…

Spark(36):Structured Streaming 编程模型

目录 0. 相关文章链接 1. 的核心思想 2. 基本概念 2.1. 输入表 2.2. 结果表 2.3. 输出 2.4. 快速入门代码的再次说明 3. 处理事件-时间和延迟数据(Handling Event-time and Late Data) 4. 容错语义 0. 相关文章链接 Spark文章汇总 1. 的核心思想 Structured Streami…

4、非线性数据结构

上一节课我们讲了线性数据结构&#xff0c;这一节我们说下非线性数据结构。 非线性数据结构&#xff0c;从字面意思来看&#xff0c;就是指不是线性的结构。线性结构的特点是只有一个前驱和一个后继。 那么非线性结构的特点就是有多个前驱或后继了。 如果只存在一个没有前驱的…

第一次编程测试(分频器)

一&#xff0c;分频器 定义 分频器&#xff08;Divider&#xff09;是一种电子电路或设备&#xff0c;用于将输入信号的频率降低到较低的频率。它常用于数字系统、通信系统和计时应用中。原理 整数分频器使用计数器来实现频率的降低。计数器根据输入信号的边沿触发进行计数&am…

STM32MP157驱动开发——按键驱动(中断)

文章目录 编写使用中断的按键驱动程序编程思路设备树相关驱动代码相关 代码修改设备树文件gpio_key_drv.cMakefile编译测试 编写使用中断的按键驱动程序 对于使用中断的按键驱动&#xff0c;内核自带的驱动程序 drivers/input/keyboard/gpio_keys.c 就可以&#xff0c;需要做的…

❛‿˂̵✧ THU数据结构(上)(2023spring) 完成啦(⑅˃◡˂⑅)

实际上来讲&#xff0c;是课程截止到今天晚上( ◔︎ ‸◔︎) 总结一下&#xff0c;放假十来天&#xff0c;边敲边听。后期有些地方应该再复习复习。 接下来的关于数据结构的目标 〇 把&#xff08;上&#xff09;中没敲完的结构敲完 〇 ZJU的配套题目写完 〇 学习&#xff…

linux系统GHOST备份方案

linux系统GHOST备份方案 Windows系统备份可以用ghost工具软件完成&#xff0c;Linux系统不能完全依赖于ghost工具&#xff0c;一则是ghost本身是有版权的软件&#xff0c;二则ghost只支持ext2、ext3文件系统的Linux分区&#xff0c;不支持reiserfs、xfs等比较高级的文件系统&a…

9.python设计模式【外观模式】

内容&#xff1a;为子系统中的一组接口提供一个一致的界面&#xff0c;外观模式定义了一个高层接口&#xff0c;这个接口使得这一个子系统更加容易使用。 角色&#xff1a; 外观&#xff08;facade&#xff09;子类系统&#xff08;subsystem classes&#xff09; UML图 举…

拉密

拉密&#xff0c;又称以色列麻将。 游戏人数为2-4人。 和扑克牌一样&#xff0c;一套是52张&#xff0c;4个花色&#xff0c;每个花色1到13。 拉密数字牌由106张塑料牌组成&#xff0c;包含2套牌和2张万能牌。 一张是可以指定成暖色任意牌&#xff0c;一张可以指定成冷色任意…

草稿#systemverilog# 说说《队列》 那些事儿

最近不断使用到systemverilog 语言编程中的队列语法。今天抽时间,尽肯能全的整理一下队列的相关用法,一是加固基础打牢,而是在代码编写过程中,提高代码水平。 队列是一种复合数据结构,可以用来存储多个数据的容器,但同时又拥有自己的优势特性。正如绿皮书所言,队列的引…

1-2 AUTOSAR分层架构

目录 一、简介 二、基础软件层 BSW 2.1 微控制器抽象层 2.2 ECU抽象层 2.3 复杂的驱动程序 2.4 服务层 三、运行时环境 RTE 四、应用软件层 SWC 一、简介 AUTOSAR架构在最高的抽象级别上区分了三个软件层&#xff1a; 应用程序层&#xff08;APPL&#xff09;运行时环…

macOS Monterey 12.6.8 (21G725) Boot ISO 原版可引导镜像

macOS Monterey 12.6.8 (21G725) Boot ISO 原版可引导镜像 本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安装&#xff0c;或者在虚拟机中启动安装。另外也支持在 Windows 和 Lin…

我的个人项目

项目介绍&#xff1a; 项目主要是使用vue3开发&#xff0c;利用前端技术&#xff0c;实现一些功能和游戏&#xff0c;并不是真正意义上的项目 功能概况介绍&#xff1a; 1. 记账&#xff08;app端页面记录日常消费和收入&#xff09; 2. 常用网站的管理 3. 文本内容检索 4. …

iptables安全技术和防火墙

防火墙&#xff1a;隔离功能 位置&#xff1a;部署在网络边缘或主机边缘&#xff0c;在工作中&#xff0c;防火墙的主要作用是决定哪些数据可以被外网访问以及哪些数据可以进入内网访问&#xff0c;主要在网络层工作 其他类型的安全技术&#xff1a;1、入侵检测系统 2、入侵…

vue2生命周期图

生命周期全过程如下&#x1f447;详解 一:生命周期之创建阶段 1.创建一个Vue实例【new Vue()】 2.初始化Vue实例,第一次初始化,初始化Vue当中的事件和生命周期方法【Init Events Lifecycle】 ☆☆☆调用生命周期方法当中的beforCreate,调用这个方法的时候有一个特点,就是在调…

自动化运维工具--saltstack部署及使用

目录 一、saltstack简介 1、介绍 2、Salt的核心功能 3、saltstack通信机制 二、saltstack部署 1、部署环境 2、配置yum源 3、安装master与minion 4、连接认证master和minion 三、salt运行 1、执行格式 2、实操演示 一、saltstack简介 1、介绍 saltstack是一个配置管…

[护网杯 2018]easy_tornado1

进入环境后有三个路径链接 访问/flag提示会说flag在/fllllllllllag里 值得注意的是访问后网页url发生的变化&#xff0c;这里居然有两个参数 替换掉filename的值后页面url再次发生变化&#xff0c;网页只有一个msg传参的数据 访问welcome.txt&#xff0c;只是回显了一个render…