数据结构与算法学习笔记三---循环队列的表示和实现(C++)

news/2024/10/11 13:22:10/

目录

前言

1.为什么要使用循环队列

2.队列的顺序存储方式的实现

1.定义

2.队列初始化

3.销毁

4.清空队列

5.队列是否为空

6.队列长度

7.队头

8.入队

9.出队

10.遍历队列

11.完整代码

3.参考资料


前言

    这篇文章介绍循环队列的表示和用法

1.为什么要使用循环队列

        在上一篇文章中,我们知道了顺序的循环表示和实现方法。但是我们会发现当我们在操作顺序链表的时候,我们频繁的操作顺序队列,而队列又不为空的时候,出队列的一些存储空间会变得不可用。

        如下图所示,当我rear=3,front=2的时候,顺序队列中至少有连个存储空间空间是不可以使用的,这无疑会浪费一些存储空间。那么有没有办法让我们在出队列之后,重复利用之前存储空间呢,答案是有的。

        图1.顺序队列的出队列和入队列操作示意图

        这里借鉴了网上老师的三种解决方案:

        1.使用计数器记录队列中的元素个数

        2.加标志位,删除的时候标志位置1,插入置0,当front = rear并且标志位为0,表示队列为空,当front=rear并且标志位为1的时候,表示队列经满。

        3.认为浪费一个存储空间,改成一个循环队列来实现。

        这里下面代码的表示和实现采用的第三种方案。

        关于循环队列的理解,感觉严蔚敏老师的讲解还是不错的,直接贴个图吧。

图2.严蔚敏老师数据结构与算法中关于循环队列的思路

2.队列的顺序存储方式的实现

1.定义

struct CircularQueue {int *base;int front;int rear;int maxSize; // 队列的最大容量
};

2.队列初始化

// 队列初始化
Status initQueue(CircularQueue &circularQueue, int maxSize) {circularQueue.base = new int[maxSize]; // 为循环队列分配内存if (!circularQueue.base) {return 0; // 内存分配失败}circularQueue.front = circularQueue.rear = 0; // 初始化队首和队尾指针circularQueue.maxSize = maxSize;return 1; // 初始化成功
}

3.销毁

// 销毁队列
void destroyQueue(CircularQueue &circularQueue) {if (circularQueue.base) {delete[] circularQueue.base; // 释放内存circularQueue.base = nullptr; // 将指针置为空}
}

4.清空队列

// 清空队列
void clearQueue(CircularQueue &circularQueue) {circularQueue.front = circularQueue.rear = 0; // 重置队首和队尾指针
}

5.队列是否为空

// 判断队列是否为空
bool isEmptyQueue(CircularQueue &circularQueue) {return circularQueue.front == circularQueue.rear; // 当队首和队尾指针相同时,队列为空
}

6.队列长度

// 获取队列长度
int queueLength(CircularQueue &circularQueue) {return (circularQueue.rear - circularQueue.front + circularQueue.maxSize) % circularQueue.maxSize;
}

7.队头

// 获取队首元素
Status getQueueFront(CircularQueue &circularQueue, int &frontElement) {if (isEmptyQueue(circularQueue)) {return 0; // 队列为空}frontElement = circularQueue.base[circularQueue.front];return 1; // 成功获取队首元素
}

8.入队

// 入队
bool enQueue(CircularQueue &circularQueue, int element) {// 检查队列是否已满if ((circularQueue.rear + 1) % circularQueue.maxSize == circularQueue.front) {return false; // 队列已满}// 入队操作circularQueue.base[circularQueue.rear] = element;circularQueue.rear = (circularQueue.rear + 1) % circularQueue.maxSize; // 移动队尾指针return true; // 入队成功
}

9.出队

// 出队
bool deQueue(CircularQueue &circularQueue, int &element) {// 检查队列是否为空if (isEmptyQueue(circularQueue)) {return false; // 队列为空,无法出队}// 出队操作element = circularQueue.base[circularQueue.front];circularQueue.front = (circularQueue.front + 1) % circularQueue.maxSize; // 移动队首指针return true; // 出队成功
}

10.遍历队列

// 遍历队列
void traverseQueue(CircularQueue &circularQueue) {// 遍历队列并打印元素int i = circularQueue.front;while (i != circularQueue.rear) {cout << circularQueue.base[i] << " ";i = (i + 1) % circularQueue.maxSize;}cout << endl;
}

11.完整代码

#include <iostream>
using namespace std;typedef int Status;struct CircularQueue {int *base;int front;int rear;int maxSize; // 队列的最大容量
};// 队列初始化
Status initQueue(CircularQueue &circularQueue, int maxSize) {circularQueue.base = new int[maxSize]; // 为循环队列分配内存if (!circularQueue.base) {return 0; // 内存分配失败}circularQueue.front = circularQueue.rear = 0; // 初始化队首和队尾指针circularQueue.maxSize = maxSize;return 1; // 初始化成功
}// 销毁队列
void destroyQueue(CircularQueue &circularQueue) {if (circularQueue.base) {delete[] circularQueue.base; // 释放内存circularQueue.base = nullptr; // 将指针置为空}
}// 清空队列
void clearQueue(CircularQueue &circularQueue) {circularQueue.front = circularQueue.rear = 0; // 重置队首和队尾指针
}// 判断队列是否为空
bool isEmptyQueue(CircularQueue &circularQueue) {return circularQueue.front == circularQueue.rear; // 当队首和队尾指针相同时,队列为空
}// 获取队列长度
int queueLength(CircularQueue &circularQueue) {return (circularQueue.rear - circularQueue.front + circularQueue.maxSize) % circularQueue.maxSize;
}// 获取队首元素
Status getQueueFront(CircularQueue &circularQueue, int &frontElement) {if (isEmptyQueue(circularQueue)) {return 0; // 队列为空}frontElement = circularQueue.base[circularQueue.front];return 1; // 成功获取队首元素
}// 入队
bool enQueue(CircularQueue &circularQueue, int element) {// 检查队列是否已满if ((circularQueue.rear + 1) % circularQueue.maxSize == circularQueue.front) {return false; // 队列已满}// 入队操作circularQueue.base[circularQueue.rear] = element;circularQueue.rear = (circularQueue.rear + 1) % circularQueue.maxSize; // 移动队尾指针return true; // 入队成功
}// 出队
bool deQueue(CircularQueue &circularQueue, int &element) {// 检查队列是否为空if (isEmptyQueue(circularQueue)) {return false; // 队列为空,无法出队}// 出队操作element = circularQueue.base[circularQueue.front];circularQueue.front = (circularQueue.front + 1) % circularQueue.maxSize; // 移动队首指针return true; // 出队成功
}// 遍历队列
void traverseQueue(CircularQueue &circularQueue) {// 遍历队列并打印元素int i = circularQueue.front;while (i != circularQueue.rear) {cout << circularQueue.base[i] << " ";i = (i + 1) % circularQueue.maxSize;}cout << endl;
}int main() {CircularQueue circularQueue;int maxSize = 10; // 队列的最大容量initQueue(circularQueue, maxSize); // 初始化循环队列// 测试入队for (int i = 1; i <= 5; ++i) {enQueue(circularQueue, i * 10);}// 输出队列元素cout << "队列元素:";traverseQueue(circularQueue);// 获取队首元素int frontElement;if (getQueueFront(circularQueue, frontElement)) {cout << "队首元素:" << frontElement << endl;}// 测试出队int element;for (int i = 0; i < 3; ++i) {if (deQueue(circularQueue, element)) {cout << "出队元素:" << element << endl;}}// 输出队列元素cout << "队列元素:";traverseQueue(circularQueue);// 判断队列是否为空if (isEmptyQueue(circularQueue)) {cout << "队列为空" << endl;} else {cout << "队列不为空" << endl;}// 获取队列长度cout << "队列长度:" << queueLength(circularQueue) << endl;// 清空队列clearQueue(circularQueue);// 判断清空后队列是否为空if (isEmptyQueue(circularQueue)) {cout << "清空队列后,队列为空" << endl;} else {cout << "清空队列后,队列不为空" << endl;}// 销毁队列destroyQueue(circularQueue);return 0;
}

3.参考资料

1.B站上看到的一个老师的讲解

2.数据结构C语言版(1997年清华大学出版社出版的图书)_百度百科


http://www.ppmy.cn/news/1460550.html

相关文章

[AIGC] 《MyBatis-Plus 结合 Spring Boot 的动态数据源介绍及 Demo 演示》

在现代的 Web 应用开发中&#xff0c;Spring Boot 已经成为了一种流行的框架选择。而 MyBatis-Plus 则为 MyBatis 框架提供了更强大的功能和便利。当它们结合使用时&#xff0c;动态数据源的运用变得更加简单和高效。 动态数据源的概念允许我们在运行时根据不同的条件或需求选…

vty、带内/带外管理、带内/带外ip简介

1、vty是什么&#xff1f; (virtual teletype)虚拟电传打字机 漫谈VTY (qq.com) 视频链接&#xff1a;使用20世纪30年代的电传打字机作为Linux系统的终端 https://hackaday.com/2020/04/15/logging-into-linux-with-a-1930s-teletype/ 2、console端口和vty端口的区别&#xf…

文心一言指令:解锁AI写作的新纪元

文心一言指令&#xff1a;解锁AI写作的新纪元 一、引言 在人工智能&#xff08;AI&#xff09;飞速发展的今天&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术取得了显著的进步。文心一言&#xff0c;作为NLP领域的一颗璀璨明星&#xff0c;以其强大的文本生成和指令…

Spring IoCDI—DI详解

在Spring框架中&#xff0c;依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;是一种重要的设计模式&#xff0c;它通过将对象的依赖关系从代码中硬编码移动到配置文件中&#xff0c;从而实现了松耦合、易于维护和测试的代码。下面我将详细介绍Spring中的依…

Docker:docker在项目中常用的一些命令

简介   Docker 是一个开源的容器化平台&#xff0c;它允许开发者将应用程序及其依赖项打包到一个可移植的容器中&#xff0c;并发布到任何安装了 Docker 引擎的机器上。这些容器是轻量级的&#xff0c;包含了应用程序运行所需的所有东西&#xff0c;如代码、系统库、系统工具…

文心一言指令

文心一言&#xff08;ERNIE Bot&#xff09;是百度公司开发的人工智能语言模型&#xff0c;它可以接收各种指令来执行不同的任务。以下是一些可能的指令示例&#xff1a; 知识问答&#xff1a; 指令&#xff1a;“请问什么是人工智能&#xff1f;”文心一言会回答关于人工智能…

基于Springboot的滴答拍摄影

基于SpringbootVue的滴答拍摄影设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 首页 摄影作品 摄影服务 摄影论坛 后台登录 后台首页 用户管理 摄影师管理 摄影作…

商业时代杂志社投稿信箱邮箱

商业时代杂志投稿信箱邮箱 商业时代杂志 《商业时代》、投稿信箱&#xff1a;sysdbjb126.com 《商业时代》、投稿信箱&#xff1a;sysdbjb126.com 《商业时代》、投稿信箱&#xff1a;sysdbjb126.com 《商业时代》、投稿信箱&#xff1a;sysdbjb126.com 咨询电话&#xf…