当前位置: 首页 > news >正文

C++基础:(十五)queue的深度解析和模拟实现

目录

前言

一、 queue 的概念与特性

二、 queue 的核心接口与使用示例

2.1 基本使用示例

2.2 注意事项

三、 queue 的模拟实现

3.1 基于 deque 的 queue 模拟实现

3.2 基于 list 的 queue 模拟实现

3.3 模拟实现的测试

四、 queue 的经典实战场景

4.1 用队列实现栈(LeetCode 225)

4.2 广度优先搜索(BFS)示例

总结


前言

        队列(queue)作为计算机科学中最基础的数据结构之一,在操作系统调度、网络数据包处理、打印机任务管理等场景中具有不可替代的作用。C++标准库中的queue容器适配器通过封装底层容器,提供了先进先出(FIFO)的严格数据管理机制。其设计哲学体现了STL的核心思想:将数据结构和算法分离,同时通过模板编程实现高度的可定制性。深入理解queue的底层实现机制,不仅能够帮助开发者更高效地使用标准库组件,更能为特定场景下的自定义队列实现提供设计范本。本文将系统分析STL queue的接口设计原理、性能特征,并给出符合STL规范的完整模拟实现方案。下面就让我们正式开始吧!


一、 queue 的概念与特性

        queue(队列)是一种遵循 “先进先出”(FIFO,First In First Out)原则的线性数据结构。类似于日常生活中的排队:先排队的人先接受服务,后排队的人后接受服务。

        queue 的核心操作集中在 “队头” 和 “队尾”:

  • 只能在队尾插入元素(入队,push);
  • 只能在队头删除元素(出队,pop);
  • 可以访问队头元素(front)和队尾元素(back)。

        queue 适用于需要 “顺序处理” 的场景,例如任务调度、消息队列、广度优先搜索(BFS)等。

二、 queue 的核心接口与使用示例

        STL 为 queue 提供的常用成员函数如下表所示:

函数声明接口说明
queue()构造一个空的队列
empty()检测队列是否为空,为空返回 true,否则返回 false
size()返回队列中有效元素的个数
front()返回队头元素的引用(非 const 对象调用)
const T& front() const返回队头元素的 const 引用(const 对象调用)
back()返回队尾元素的引用(非 const 对象调用)
const T& back() const返回队尾元素的 const 引用(const 对象调用)
push(const T& x)将元素 x 插入队尾
pop()删除队头元素(不返回元素值)

2.1 基本使用示例

#include <iostream>
#include <queue>
using namespace std;int main() {// 构造空队列queue<int> q;// 入队操作q.push(10);q.push(20);q.push(30);cout << "队列的大小:" << q.size() << endl;  // 输出:3cout << "队头元素:" << q.front() << endl;    // 输出:10cout << "队尾元素:" << q.back() << endl;     // 输出:30// 出队操作q.pop();cout << "出队后队头元素:" << q.front() << endl;  // 输出:20cout << "出队后队列的大小:" << q.size() << endl;  // 输出:2// 遍历队列(通过出队方式)while (!q.empty()) {cout << "出队元素:" << q.front() << endl;q.pop();}cout << "队列是否为空:" << (q.empty() ? "是" : "否") << endl;  // 输出:是return 0;
}

2.2 注意事项

  1. pop()函数只删除队头元素,不返回该元素的值。若需获取队头元素并删除,需先调用front()获取值,再调用pop()删除;
  2. 访问front()back()前,必须确保队列不为空,否则会导致未定义行为;
  3. queue 同样不支持遍历操作(没有迭代器),只能通过不断出队来访问所有元素。

三、 queue 的模拟实现

        queue 的核心操作是 “尾插” 和 “头删”,因此底层容器需要支持push_back()(尾插)pop_front()(头删)front()(访问头元素)back()(访问尾元素)等操作。

        vector 的pop_front()操作效率极低(需要搬移所有元素,时间复杂度 O (n)),因此不适合作为 queue 的底层容器。STL 中 queue 的默认底层容器是 deque,也可以指定 list 作为底层容器。

3.1 基于 deque 的 queue 模拟实现

#include <deque>
#include <cassert>
namespace bite {template <class T, class Container = std::deque<T>>class queue {public:// 构造函数:默认构造queue() {}// 入队:调用底层容器的push_backvoid push(const T& x) {_container.push_back(x);}// 出队:调用底层容器的pop_front,需确保队列不为空void pop() {assert(!empty());_container.pop_front();}// 访问队头元素:调用底层容器的front,需确保队列不为空T& front() {assert(!empty());return _container.front();}// const版本的frontconst T& front() const {assert(!empty());return _container.front();}// 访问队尾元素:调用底层容器的back,需确保队列不为空T& back() {assert(!empty());return _container.back();}// const版本的backconst T& back() const {assert(!empty());return _container.back();}// 获取队列大小size_t size() const {return _container.size();}// 检测队列是否为空bool empty() const {return _container.empty();}private:Container _container;  // 底层容器};
}

3.2 基于 list 的 queue 模拟实现

        list 的push_back()pop_front()操作均为 O (1) 时间复杂度,适合作为 queue 的底层容器。模拟实现如下:

#include <list>
#include <cassert>
namespace bite {template <class T, class Container = std::list<T>>class queue {public:queue() {}void push(const T& x) {_container.push_back(x);}void pop() {assert(!empty());_container.pop_front();}T& front() {assert(!empty());return _container.front();}const T& front() const {assert(!empty());return _container.front();}T& back() {assert(!empty());return _container.back();}const T& back() const {assert(!empty());return _container.back();}size_t size() const {return _container.size();}bool empty() const {return _container.empty();}private:Container _container;};
}

3.3 模拟实现的测试

#include <iostream>
#include "queue.hpp"
using namespace std;
using namespace bite;int main() {queue<int> q;q.push(1);q.push(2);q.push(3);cout << "size: " << q.size() << endl;        // 3cout << "front: " << q.front() << endl;      // 1cout << "back: " << q.back() << endl;        // 3q.pop();cout << "after pop, front: " << q.front() << endl;  // 2cout << "after pop, back: " << q.back() << endl;    // 3const queue<int> cq = q;cout << "const queue front: " << cq.front() << endl;  // 2cout << "const queue back: " << cq.back() << endl;    // 3while (!q.empty()) {cout << q.front() << " ";q.pop();}// 输出:2 3return 0;
}

四、 queue 的经典实战场景

        queue 的 “先进先出” 特性使其在顺序处理场景中不可或缺,以下是几个典型应用。

4.1 用队列实现栈(LeetCode 225)

题目描述:请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

解题思路

  • 核心需求:用队列(FIFO)模拟栈(LIFO),关键是让每次入队的元素成为队头(即最后入队的元素最先出队);
  • 设计思路:
    1. 用两个队列q1q2q1作为主队列,存储当前栈中的元素;
    2. 压栈(push):将元素入队到q2,然后将q1中的所有元素依次出队并入队到q2,最后交换q1q2,使新元素成为q1的队头;
    3. 出栈(pop):直接弹出q1的队头元素(即栈顶元素);
    4. 访问栈顶(top):返回q1的队头元素;
    5. 检测为空(empty):判断q1是否为空。

代码实现

#include <queue>
#include <cassert>
using namespace std;class MyStack {
public:MyStack() {}void push(int x) {queue<int> q2;// 新元素入队q2q2.push(x);// 将q1的所有元素转移到q2while (!q1.empty()) {q2.push(q1.front());q1.pop();}// 交换q1和q2,q1成为主队列swap(q1, q2);}void pop() {assert(!empty());q1.pop();}int top() {assert(!empty());return q1.front();}bool empty() {return q1.empty();}private:queue<int> q1;  // 主队列,存储栈元素
};// 测试代码
int main() {MyStack st;st.push(1);st.push(2);st.push(3);cout << st.top() << endl;  // 输出:3st.pop();cout << st.top() << endl;  // 输出:2st.pop();cout << st.top() << endl;  // 输出:1cout << (st.empty() ? "empty" : "not empty") << endl;  // 输出:not emptyst.pop();cout << (st.empty() ? "empty" : "not empty") << endl;  // 输出:emptyreturn 0;
}

4.2 广度优先搜索(BFS)示例

广度优先搜索是一种层级遍历算法,核心思想是 “先访问当前节点的所有邻接节点,再依次访问邻接节点的邻接节点”,queue 是实现 BFS 的理想数据结构。

示例:二叉树的层序遍历(LeetCode 102)

#include <iostream>
#include <queue>
#include <vector>
using namespace std;// 二叉树节点定义
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> result;if (root == nullptr) {return result;}queue<TreeNode*> q;q.push(root);  // 根节点入队while (!q.empty()) {int levelSize = q.size();  // 当前层的节点数vector<int> levelNodes;    // 存储当前层的节点值// 遍历当前层的所有节点for (int i = 0; i < levelSize; ++i) {TreeNode* node = q.front();q.pop();levelNodes.push_back(node->val);// 左子节点入队if (node->left != nullptr) {q.push(node->left);}// 右子节点入队if (node->right != nullptr) {q.push(node->right);}}result.push_back(levelNodes);}return result;}
};// 测试代码
int main() {// 构建二叉树TreeNode* root = new TreeNode(3);root->left = new TreeNode(9);root->right = new TreeNode(20);root->right->left = new TreeNode(15);root->right->right = new TreeNode(7);Solution sol;vector<vector<int>> result = sol.levelOrder(root);// 输出层序遍历结果for (auto& level : result) {for (auto& val : level) {cout << val << " ";}cout << endl;}// 输出:// 3 // 9 20 // 15 7 return 0;
}

总结

        本期博客我为大家介绍了C++queue容器适配器的相关接口和模拟实现,下期博客将继续容器适配器的学习,为大家介绍priority_queue和deque的相关知识,请大家多多关注哦!

http://www.dtcms.com/a/499092.html

相关文章:

  • VSR 项目解析
  • 软件工程新纪元:AI协同编程架构师的修养与使命
  • 一、RPA基础认知与环境搭建
  • 网站域名过期了怎么办怎样做网站导航界面
  • armbian 滚动更新锁定
  • Rust 设计模式 Marker Trait + Blanket Implementation
  • 在 MacOS Tahoe 上使用VMware虚拟机安装 ARM版 Windows11
  • 苏州手机网站建设报价下载好的字体怎么安装到wordpress
  • 品牌出海进入精细化阶段,全球业财一体化成为系统选型关键
  • K8S(十二)—— Kubernetes安全机制深度解析与实践:从认证到RBAC授权
  • 【Zephyr存储专题】16_内存泄露检测可视化脚本自动化
  • 云服务器怎么建网站wordpress 仿 主题下载
  • 怎么搭建手机网站m国内最近重大新闻2024
  • 企业微信ipad协议接口优势
  • AI协同编程架构师如何解决技术债问题
  • 官方网站下载打印机驱动网站服务商
  • 解决部分程序中文乱码的问题
  • 三次到达:理解二叉树非递归遍历
  • AI驱动的专业报告撰写:从信息整合到洞察生成的全新范式
  • JVM(Java虚拟机)~
  • 南充网站建设略奥网络地宝网招聘信息网
  • mmdetection训练 测试步骤
  • 【基础算法】01BFS
  • Openharmony应用开发之Ability异常退出与UIAbility数据备份开发实战
  • 我做了一个免费的 DeepResearch 网站,让科研变得更简单
  • 顺德大良那里做网站好福建省城乡和住房建设厅网站
  • 前端+AI:CSS3(二)
  • go邮件发送——附件与图片显示
  • AI+若依框架(基础篇)
  • 机器学习(2) 线性回归和代价函数