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

目录

前言

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年清华大学出版社出版的图书)_百度百科

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

短视频赛道有哪些:成都鼎茂宏升文化传媒公司

短视频赛道有哪些&#xff1a;探索多元化的内容领域 随着科技的飞速发展和人们生活节奏的加快&#xff0c;短视频已成为现代人生活中不可或缺的一部分。它以其简短、直观、易于分享的特点&#xff0c;迅速占领了各个年龄层和社会群体的心智。然而&#xff0c;短视频的赛道并非…

vue2基础语法03——过滤器filter

vue2基础语法03——过滤器filter 1. 前言1.1 需求1.2 不用过滤器实现1.2.1 插值语法、计算属性、方法实现1.2.2 更多关于计算属性 和 方法 2. 使用过滤器实现2.1 说明2.2 例子12.3 例子2——优化2.3.1 默认字母不分割2.3.2 默认字母以分割 2.4 过滤器使用地方 3. 全局过滤器4. …

C++智能指针之唯一指针(std::unique_ptr)

1 概述 从C11开始C语言越来向现代化语言转变。尤其是智能指针的引入&#xff0c;代码中不会直接使用new/delete了。C11智能指针有三种分别是&#xff1a;shared_ptr&#xff0c;weak_ptr 和unique_ptr 。 2 唯一指针(unique_ptr) unique_ptr是C11引入的&#xff0c;用来管理指…

上位机图像处理和嵌入式模块部署(树莓派4b安装dockerros1、ros2)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们讨论过树莓派4b安装ros的问题&#xff0c;当时的解决方案就是利用docker来安装ros。我们都知道&#xff0c;每一个ros版本都是和特定的ubu…

mysql权限体系

提示&#xff1a;根据课程视频总结知识点------2024.05.15 文章目录 权限处理逻辑1、 能不能连接2、能不能执行操作 权限授予与回收1、创建用户2、授予权限3、查看权限4、回收权限5、 权限级别 账户安全管理1、用户权限设定原则2、历史文件泄密 用户权限设定原则1. 只读用户--数…

C++|树形关联式容器(set、map、multiset、multimap)介绍使用

目录 一、关联式容器介绍 1.1概念 1.2键值对 1.3树形结构的关联式容器 1.3.1pair模板介绍 1.3.2make_pair的介绍 二、set的介绍和使用 2.1set介绍 2.2set使用 2.2.1构造 2.2.2容量 2.2.3修改 三、map的介绍和使用 3.1map介绍 3.2map使用 3.2.1构造 3.2.2容量 …

VC++6.0 Sqlite3调用例子

1,为什么要使用Sqlite3? SQLite 是一个软件库&#xff0c;实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。SQLite 源代码不受版权限制。 2,为什么使用SQLite version 3.8.4.3 2014-04-03 16:53:12的版本…

邮件发送API的功能有哪些?API的调用限制?

邮件发送API的响应速度如何&#xff1f;如何选择API发送邮件&#xff1f; 邮件发送API提供了高效、灵活且可靠的邮件发送功能&#xff0c;使得邮件营销、用户通知、系统告警等场景变得轻松自如。那么&#xff0c;邮件发送API具体都有哪些功能呢&#xff1f;让AokSend来探索吧&…

Spark SQL ---结构化数据文件处理

DataFrame概述 DataFrame的创建 创建DataFrame的两种基本方式&#xff1a; •已存在的RDD调用toDF()方法转换得到DataFrame。 •通过Spark读取数据源直接创建DataFrame。 若使用SparkSession方式创建DataFrame&#xff0c;可以使用spark.read从不同类型的文件中加载数据创建…

【美团面试2024/05/14】前端面试题滑动窗口

一、题目描述 设有一字符串序列 s&#xff0c;确定该序列中最长的无重复字母的子序列&#xff0c;并返回其长度。 备注 0 < s.length < 5 * 104 s 由英文字母、数字、符号和空格组成 示例1 输入 s "abcabcbb" 输出 3 二、原题链接 这道题在LeetCode上的原题链…

运维别卷系列 - 云原生监控平台 之 06.prometheus pushgateway 实践

文章目录 [toc]Pushgateway 简介Pushgateway 部署创建 svc创建 deployment Pushgateway 测试删除 Pushgateway 上对应 lable 的数据 Pushgateway 简介 WHEN TO USE THE PUSHGATEWAY Pushgateway 是一种中介服务&#xff0c;允许您从无法抓取的作业中推送指标。 The Pushgateway…

Python NumPy数组的创建方法

Numpy是Python中科学计算的基础包&#xff0c;其核心对象就是ndarray&#xff08;n维数组&#xff09;。利用数组可以快速执行逻辑&#xff0c;形状操作&#xff0c;统计和傅里叶变换等运算&#xff0c;其效率比Python原生的数组效率更高。因此使用Numpy的第一件事就是创建Nump…

构建第一个ArkTS应用之@LazyForEach:数据懒加载

LazyForEach从提供的数据源中按需迭代数据&#xff0c;并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach&#xff0c;框架会根据滚动容器可视区域按需创建组件&#xff0c;当组件滑出可视区域外时&#xff0c;框架会进行组件销毁回收以降低内存占用。 接口…

线性/非线性最小二乘 与 牛顿/高斯牛顿/LM 原理及算法

最小二乘分为线性最小二乘和非线性最小二乘 最小二乘目标函数都是min ||f(x)||2 若f(x) ax b&#xff0c;就是线性最小二乘&#xff1b;若f(x) ax2 b / ax2 bx 之类的&#xff0c;就是非线性最小二乘&#xff1b; 1. 求解线性最小二乘 【参考】 2. 求解非线性最小二乘…

玩转大模型 企业AI着陆新正解 神州问学AI原生赋能平台正式发布

在人工智能技术日新月异的今天&#xff0c;神州数码凭借深厚的行业洞察和技术积累&#xff0c;揭开了AI原生赋能平台——神州问学的神秘面纱。作为企业AI着陆的加速引擎&#xff0c;神州问学致力于通过AI原生场景赋能&#xff0c;为企业开辟一条通往智能未来的坦途。 神州问学—…

出国旅游常用英语,柯桥成人英语培训

Where can I catch a taxi?哪里我可以叫到出租车&#xff1f; The taxi zone is right on the left corner over there.出租车站台就在左边转角处。 Are you free?您有空吗&#xff1f; Sure. Where are you going?当然。您要去哪里&#xff1f; Drive me back to Santa …

2024年淘宝京东天猫618红包领取跨店满减优惠券活动时间是从什么时候开始到几月几号结束?

2024年淘宝、天猫、京东618红包领取口令及活动时间已发布&#xff0c;具体如下&#xff1a; 一、2024年淘宝天猫618活动 1.1、2024年淘宝天猫618活动时间 2024年5月20日开始持续到6月20日结束&#xff1b; 1.2、2024年淘宝天猫618红包领取 在活动时间内&#xff0c;每天都可…

如何通过radsystem源代码启动项目

大家有没有想过这样一个问题&#xff0c;如果别人没有下载radsystems&#xff0c;别人该如何打开我们的项目呢&#xff0c;那么今天我来介绍一下&#xff0c;如何启动radsystem源代码。 一般来说我们都是需要打开radsystems的publish部署项目 但是我们可以通过它部署后的源代码…

内存函数:memcpy(拷贝),memmove(拷贝),memcmp(比较),memset(设置)

内存函数 一.memcpy&#xff08;内存拷贝1&#xff09;1.函数使用2.模拟实现 二.memmove&#xff08;内存拷贝2&#xff09;1.函数使用2.模拟实现 三.memcmp&#xff08;内存比较&#xff09;1.函数使用2.模拟实现 四.memset&#xff08;内存设置&#xff09;1.函数使用2.模拟实…

axios封装 手动取消接口请求

axios封装 手动取消接口请求 1.创建clearHttpRequest.js文件2.封装的axios文件中使用3.vue文件中引入4. 路由切换使用 对于一些接口loading很久&#xff0c;用户想手动终止请求的需求&#xff0c; 并为了节约性能&#xff0c;当路由切换时&#xff0c;cancel掉还没有结束的接口…