0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

队列与C++中的queue详解

冬至子 来源:iDoitnow 作者:艰默 2023-07-18 17:31 次阅读

队列(Queue)

什么是队列

队列就是一种线性的数据结构,它与日常生活中排队的队列相似,即先进先出(LIFO, First In First Out),这点也是它与栈Stack的最大不同之处。它的结构类似于下面的容器:

图片

如上图所示,队列的结构就像一个两端都是开口的容器,一端只负责小球(对应队列中的元素)进入,一个端只负责小球弹出,容器内部的小球无法跳过前面的小球提前弹出。我们将队列的出口端(即队列的头部)叫做队头(front),入口端(即队列的末尾)称为队尾(rear)。

与栈类似,队列的底层数据结构也可以使用数组和链表来实现,具体如下图所示:

图片

队列的基本操作和应用

队列的基本操作与栈类似,主要是分为入队(enqueue)和出队(dequeue),我们以数组为例,简单描述一下具体过程。

1. 入队

入队就是把新元素放入队列中去,由于队列的数据结构的限制,只允许将新入队元素放入队尾的位置,然后更新队尾的位置,具体过程如下图所示。

图片

2. 出队

出队就是把队列中的元素移出来,同样的,队列只允许在队列的队头这一侧移出元素,即每次移出的元素就是队头对应的元素,元素移出后,原对头元素的后面一个元素变为新的队头,具体过程如下所示:

图片

3. 入队出队的复杂度和应用

与栈类似,队列的入队与出队只与队头和队尾的元素相关,不涉及其他元素的移动,因此队列的入队和出队的时间复杂度都是。

队列先进先出的特性使得其常用于一下场景中:

  • 消息队列:在分布式系统或异步任务处理场景中,消息队列可以用于解耦任务的发布与消费,确保任务能够稳定地进行下去。
  • 程序调度:操作系统、多线程程序、并发网络程序等需要协调多个任务的程序中,通常会使用队列来维护任务的执行顺序,以保证每个任务都能够得到执行。
  • 广度优先搜索:在图论、路径查找等问题中,广度优先搜索算法通常会使用队列来存储待搜索的节点,以确保每一层的所有节点都可以被访问到。
  • 缓存:在许多应用中,缓存通常使用队列来管理缓存项的过期时间和更替策略,使得缓存可以高效地使用有限的内存资源。

类模板std::queue

std::queue类是C++提供的容器适配器,它提供了特定的函数集合,实现了队列的基本功能:FIFO的数据结构,即在容器的尾端推入元素,在首段弹出元素。std::queue类在头文件中定义,其函数声明如下:

template<
    class T,
    class Container = std::deque< T >
> class queue;

形参T和Container

  • T :存储的元素类型。
  • Container :用于存储元素的底层容器。容器类型必须是序列容器,同时,该容器类型需提供通常语义下的back()、front()、push_back()和pop_front()函数,满足该要求的标准容器有std::deque和std::list,其中默认使用的容器是std::deque。

成员函数

1. 元素访问
  • front :访问队列第一个元素。其函数声明如下:
reference front();
const_reference front() const;

该函数返回队列中首个元素的引用,实际上该函数等效的调用的就是存储元素的底层容器(Container)的front()函数。

  • back :访问队列最后一个元素。其函数声明如下:
reference back();
const_reference back() const;

该函数返回的是队列末尾元素的引用,实际上该函数等效的调用的就是Container的back()函数。

2. 容量
  • empty :检查队列是否为空。其函数声明如下:
bool empty() const; // C++20 前
[[nodiscard]] bool empty() const; //C++20 起

其本质上就是检查Container是否为空,即Container的empty()。如果为空返回true,否则为false。

  • size :返回队列中的元素个数。其函数声明如如下:
size_type size() const;

同样的,其本质还是返回的是Container的元素个数,即Container的size()。

3. 队列的修改
  • push :向队列的尾部插入元素,对应的就是入队操作。其函数声明如下:
void push( const value_type& value );
void push( value_type&& value ); //C++11 起
  • emplace :在队列的尾部构造元素,对应的也是入队的操作。其函数声明如下:
template< class... Args >
void emplace( Args&&... args );// C++11 起  C++17 前
template< class... Args >
decltype(auto) emplace( Args&&... args );// C++17 起

该函数就是将新元素推到队列的尾部,其与push不同的是:该函数是原地构造元素,即不进行移动或复制操作,使用参数直接原地调用元素的构造函数,使得其效率高于push。

  • pop :删除队列首个元素,对应的就是出队操作。其函数声明如下:
void pop();

该函数移除队列前端的元素,等效的调用了Container的pop_front()函数。

  • swap :交换两个容器的内容。其函数声明如下:
void swap( queue& other ) noexcept(); //C++11 起

其本质上是交换两个Container中的内容。

用法示例

#include < iostream >
#include < queue >
using namespace std;

void showQueue(string queueName, queue< int >& q) {
    cout < < "队列" < < queueName < < "中元素的数量, 即size() = " < < q.size()
        < < endl;
    if (!q.empty()) {
        cout < < "此时, 队列" < < queueName < < "不为空,即empty() = false" < < endl;
        cout < < "队列首位元素,即front() =  " < < q.front() < < endl;
        cout < < "队列首位元素,即back() =  " < < q.back() < < endl;
    } else {
        cout < < "此时, 队列" < < queueName < < "为空,即empty() = true" < < endl;
    }
}

int main() {
    queue< int > q;

    // push()
    q.push(1);
    q.push(2);
    q.push(3);

    cout < < "---按顺push元素1、2、3后:n" < < endl;
    showQueue("q", q);

    q.pop();  // 弹出队头元素
    cout < < "n---弹出队头元素3, 即pop()后:n" < < endl;
    showQueue("q", q);

    q.pop();
    cout < < "n---弹出队头元素2, 即pop()后:n" < < endl;
    showQueue("q", q);

    q.pop();
    cout < < "n---弹出队头元素1, 即pop()后:n" < < endl;
    showQueue("q", q);

    queue< int > q1;
    q1.emplace(1);
    q1.emplace(2);
    q1.emplace(3);

    cout < < "n-----------队列q和q1交换前----------" < < endl;
    cout < < "nq的状态: " < < endl;
    showQueue("q", q);

    cout < < "nq1的状态: " < < endl;
    showQueue("q1", q1);

    q1.swap(q);  // s和s1进行交换

    cout < < "n-----------队列q和q1交换后----------n" < < endl;
    showQueue("q", q);

    cout < < "nq1的状态: " < < endl;
    showQueue("q1", q1);

    return 0;
}

输出结果:

---按顺push元素123后:

队列q中元素的数量, 即size() = 3
此时, 队列q不为空,即empty() = false
队列首位元素,即front() =  1
队列首位元素,即back() =  3

---弹出队头元素3, 即pop()后:

队列q中元素的数量, 即size() = 2
此时, 队列q不为空,即empty() = false
队列首位元素,即front() =  2
队列首位元素,即back() =  3

---弹出队头元素2, 即pop()后:

队列q中元素的数量, 即size() = 1
此时, 队列q不为空,即empty() = false
队列首位元素,即front() =  3
队列首位元素,即back() =  3

---弹出队头元素1, 即pop()后:

队列q中元素的数量, 即size() = 0
此时, 队列q为空,即empty() = true

-----------队列q和q1交换前----------

q的状态: 
队列q中元素的数量, 即size() = 0
此时, 队列q为空,即empty() = true

q1的状态: 
队列q1中元素的数量, 即size() = 3
此时, 队列q1不为空,即empty() = false
队列首位元素,即front() =  1
队列首位元素,即back() =  3

-----------队列q和q1交换后----------

队列q中元素的数量, 即size() = 3
此时, 队列q不为空,即empty() = false
队列首位元素,即front() =  1
队列首位元素,即back() =  3

q1的状态: 
队列q1中元素的数量, 即size() = 0
此时, 队列q1为空,即empty() = true
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 适配器
    +关注

    关注

    8

    文章

    1823

    浏览量

    66951
  • 缓存器
    +关注

    关注

    0

    文章

    63

    浏览量

    11579
  • C++语言
    +关注

    关注

    0

    文章

    146

    浏览量

    6878
  • FIFO存储
    +关注

    关注

    0

    文章

    102

    浏览量

    5895
收藏 人收藏

    评论

    相关推荐

    鸿蒙c++模板开发详解

    鸿蒙c++模板开发详解
    发表于 09-11 15:28

    Queue Management消息队列使用详解

    消息队列作为任务间同步扮演着必不可少的角色
    发表于 01-21 06:12

    Queue队列的作用是什么

    文章目录前言Queue 队列semaphore 信号量Mutex 互斥量微信公众号前言FreeRTOS STM32CubeMX配置 内存管理 任务管理上节介绍了用STM32CubeMX生成带
    发表于 02-14 06:57

    消息队列Queue相关资料推荐

    消息队列QueueAPItx_queue_createtx_queue_deletex_queue_flushtx_queue_front_sendtx_queue_receivetx_queue_send_notifyAPItx_queue_createtx_queue_del
    发表于 02-22 06:53

    RT-Thread的data_queue是什么?怎样去使用

    1. data_queue 是什么data_queue 直接翻译过来是 数据队列。这个名字和 消息队列 很像。那么他们有什么区别呢?消息队列
    发表于 04-15 15:56

    OpenHarmony:内核对象队列之算法详解(下)

    ,在上一期发布的《OpenHarmony——内核对象队列之算法详解(上)》文章,我分享了OpenHarmonyLiteOS-M内核对象队列的FIFO的算法,今天给大家介绍另外一种算法
    发表于 08-09 10:25

    OpenHarmony:内核对象队列之算法详解(上)

    [OS_QUEUE_WRITE]: 消息节点循环队列可写的消息个数,为 0 表示循环队列为满,等于 queueLen 表示循环队列为空。r
    发表于 08-09 10:29

    OpenHarmony——内核对象队列之算法详解(下)

    LiteOS-M内核对象队列的算法包括FIFO和FILO,在上一期发布的《OpenHarmony-内核对象队列之算法详解(上)》文章,我分享了OpenHarmonyLiteOS-M
    发表于 08-09 16:16

    ThreadX(九)------消息队列Queue

    消息队列QueueAPItx_queue_createtx_queue_deletex_queue_flushtx_queue_front_sendtx_queue_receivetx_queue_send_notifyAPItx_queue_createtx_queue_del
    发表于 12-28 19:35 2次下载
    ThreadX(九)------消息<b class='flag-5'>队列</b><b class='flag-5'>Queue</b>

    队列Queue的常用方法有哪些

    FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。
    的头像 发表于 08-19 10:24 5156次阅读
    <b class='flag-5'>队列</b><b class='flag-5'>Queue</b>的常用方法有哪些

    STM32G0开发笔记:使用FreeRTOS系统的队列Queue

    使用Platformio平台的libopencm3开发框架来开发STM32G0,下面为使用FreeRTOS系统的队列Queue
    的头像 发表于 01-16 14:50 969次阅读

    什么是queue

    queue 容器,又称队列容器,是简单地装饰deque容器而成为另外的一种容器。
    的头像 发表于 02-27 15:43 1000次阅读

    利用C++提供的队列封装一个消息队列

    最近的C++项目中,需要用到消息队列,但是C++中又没有原生的消息队列,就在网上找了一下相关资料,利用C++提供的
    的头像 发表于 05-20 15:16 1101次阅读
    利用<b class='flag-5'>C++</b>提供的<b class='flag-5'>队列</b>封装一个消息<b class='flag-5'>队列</b>

    FreeRTOS消息队列结构体

    有一个结构体用于描述队列,叫做 Queue_t,这个结构体在文件 queue.c 中定义。 3、队列创建 在使用队列之前必须先创建
    的头像 发表于 07-06 17:03 680次阅读
    FreeRTOS消息<b class='flag-5'>队列</b>结构体

    队列实现栈的两种方法

    两个队列实现一个栈 思路:两个队列实现一个栈,使用了队列交换的思想。 代码如下: type MyStack struct { queue1, que
    的头像 发表于 10-08 16:01 425次阅读