C++中Queue与Priority Queue的实现

 更新时间:2026年09月07日 09:49:13   作者:库克克  
本文用大白话讲解队列和优先队列的核心区别、底层容器选择、自定义类型比较方法,并附上经典算法实战,帮你彻底搞懂容器适配器

1. 简介:容器适配器

在 C++ STL 中,Queue(队列)和 Priority Queue(优先队列)都被归类为容器适配器,而非标准容器。所谓适配器模式,就是将特定容器类封装作为其底层容器类,并提供一组特定的成员函数来访问其元素。

  • Queue(队列):专门用于 FIFO(先进先出)上下文,元素的流动规则是“队尾入,队头出”。
  • Priority Queue(优先队列):底层类似堆(Heap)结构。它并不遵循先进先出,而是根据严格的弱排序标准,保证每次出队的元素都是当前队列中最大(或最小)的元素。

2. 核心接口与基本使用

2.1 Queue 的基本使用

Queue 的底层容器应至少支持:empty、size、front、back、push_back、pop_front。默认情况下,使用 deque。

接口名称功能说明
push(val) / pop()队尾入队 / 队头出队
front() / back()返回队头元素的引用 / 返回队尾元素的引用
empty() / size()检测队列是否为空 / 返回有效元素个数

2.2 Priority Queue 的基本使用

Priority Queue 的底层容器必须支持随机访问迭代器(如 empty、size、front、push_back、pop_back),因为它需要借助堆算法(make_heap, push_heap, pop_heap)来维护结构。默认情况下,使用 vector 作为底层容器,且默认是大根堆(Max-Heap)。

接口名称功能说明
push(val)在优先队列中插入元素,并自动调整堆结构
pop()删除优先队列中最大(或最小)的堆顶元素
top()返回堆顶元素(最大或最小元素)
empty() / size()检测是否为空 / 返回元素个数
#include <iostream>
#include <queue>
using namespace std;

void test_priority_queue() {
    // 默认是大堆(输出:9 8 7 6 ...)
    priority_queue<int> max_pq;
    max_pq.push(3); 
  	max_pq.push(9); 
  	max_pq.push(1);
    cout << "Max Heap Top: " << max_pq.top() << endl; // 输出 9
}

3. Priority Queue 的仿函数与自定义类型

在使用优先队列时,我们常常需要改变默认的大根堆行为,或者存储自定义的数据类型。

3.1 切换为小根堆

要创建小根堆,需要引入 <functional> 头文件,并将第三个模板参数替换为 greater<T>。

#include <queue>
#include <functional> // greater 算法的头文件

// 创建小根堆,底层按照大于号比较
std::priority_queue<int, std::vector<int>, std::greater<int>> min_pq;

3.2 自定义类型的比较

如果优先队列中存放自定义类型,用户需要在自定义类型中提供 > 或者 < 的重载,或者传入自定义的仿函数(Functor)。

class Date {
public:
    Date(int year, int month, int day) : _year(year), _month(month), _day(day) {}
    
    // 大根堆需要重载 <
    bool operator<(const Date& d) const {
        if (_year != d._year) return _year < d._year;
        if (_month != d._month) return _month < d._month;
        return _day < d._day;
    }
private:
    int _year, _month, _day;
};

void test_custom_type() {
    std::priority_queue<Date> q;
    q.push(Date(2023, 10, 1));
    q.push(Date(2023, 11, 11)); // 这个会成为堆顶
}

4. 经典算法实战

4.1 Queue 实战:

用队列实现栈

思路:使用两个队列(q1, q2)模拟栈。入栈直接进非空队列;出栈时,将非空队列前 n-1 个元素倒入空队列,弹出最后剩下的那个元素即可。

class MyStack {
public:
    void push(int x) {
        q1.empty() ? q2.push(x) : q1.push(x);
    }
    
    int pop() {
        std::queue<int>& emptyQ = q1.empty() ? q1 : q2;
        std::queue<int>& nonEmptyQ = q1.empty() ? q2 : q1;
        
        while (nonEmptyQ.size() > 1) {
            emptyQ.push(nonEmptyQ.front());
            nonEmptyQ.pop();
        }
        int topElement = nonEmptyQ.front();
        nonEmptyQ.pop();
        return topElement;
    }
    
    // top() 和 empty() 逻辑省略...
private:
    std::queue<int> q1, q2;
};

4.2 Priority Queue 实战:

数组中的第K个最大元素

思路:将数组元素全部放入大根堆(优先队列)中,然后执行 k-1 次 pop(),此时的堆顶元素就是第 K 大的元素。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        // 将数组中的元素先放入优先级队列中 (O(N) 建堆)
        std::priority_queue<int> p(nums.begin(), nums.end());
        
        // 将前 k-1 个最大的元素删除
        for(int i = 0; i < k - 1; ++i) {
            p.pop();
        }
        return p.top();
    }
};

5. 为什么 Queue 默认 Deque,而 Priority Queue 默认 Vector?

  • Queue 为什么默认 Deque 而不支持 Vector?

    queue 强依赖头删(pop_front)和尾插(push_back)。deque 在头部删除和尾部插入时效率极高,时间复杂度为 O(1)。若用 vector 封装,每次头删都需要挪动后续所有数据,时间复杂度骤降为 O(N)。

  • Priority Queue 为什么默认 Vector?

    优先队列本质是一个堆(完全二叉树的数组实现)。堆的维护依赖大量的随机访问(例如通过父节点索引 i 访问左右孩子 2i+1, 2i+2)。vector 提供了极致的随机访问性能和极高的空间缓存命中率,因此是优先队列的最佳拍档。

附录:适配器的模拟实现 (封装)

Queue 的封装

#pragma once
#include <deque>

namespace bit {
    template<class T, class Container = std::deque<T>>
    class queue {
    public:
        void push(const T& x) { _con.push_back(x); }
        void pop() { _con.pop_front(); }
        const T& back() { return _con.back(); }
        const T& front() { return _con.front(); }
        bool empty() const { return _con.empty(); }
        size_t size() const { return _con.size(); }
    private:
        Container _con;
    };
}

Priority Queue 的封装

借用 STL 的堆算法(push_heap, pop_heap)即可极其优雅地实现优先队列适配器。

#pragma once
#include <vector>
#include <algorithm> // 包含堆算法
#include <functional>

namespace bit {
    template<class T, class Container = std::vector<T>, class Compare = std::less<T>>
    class priority_queue {
    public:
        priority_queue() {}
        
        template<class InputIterator>
        priority_queue(InputIterator first, InputIterator last) : _con(first, last) {
            // 建堆
            std::make_heap(_con.begin(), _con.end(), comp);
        }

        void push(const T& x) {
            _con.push_back(x);
            std::push_heap(_con.begin(), _con.end(), comp); // 向上调整
        }

        void pop() {
            std::pop_heap(_con.begin(), _con.end(), comp);  // 将堆顶移到末尾,向下调整
            _con.pop_back();                                // 真正删除
        }

        const T& top() const {
            return _con.front();
        }

        bool empty() const {
            return _con.empty();
        }

        size_t size() const {
            return _con.size();
        }

    private:
        Container _con;
        Compare comp; // 比较器对象
    };
}

到此这篇关于C++中Queue与Priority Queue的实现的文章就介绍到这了,更多相关C++ Queue与Priority Queue内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++中vector和map的删除方法(推荐)

    C++中vector和map的删除方法(推荐)

    下面小编就为大家带来一篇C++中vector和map的删除方法(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • C++图文并茂轻松进阶面向对象

    C++图文并茂轻松进阶面向对象

    面向对象中对象是指具体的某一个事物,这些事物的抽象就是类,类中包含数据(成员变量)和动作(成员方法),接下来让我们一起详细了解
    2022-04-04
  • C语言中的状态机设计深入讲解

    C语言中的状态机设计深入讲解

    这篇文章主要给大家介绍了关于C语言状态机设计的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • C语言实现单词助手功能

    C语言实现单词助手功能

    这篇文章主要为大家详细介绍了C语言实现单词小助手,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • OpenCV mask的作用及如何制作掩模mask

    OpenCV mask的作用及如何制作掩模mask

    mask 不是马斯克,是掩膜,可以用来遮盖非感兴趣区,突出感兴趣区,使得图像处理只专注于ROI部分,OpenCV中的很多函数用到mask,mask是什么?怎么制作一个mask?本文给大家分享OpenCV mask的作用及如何制作掩模mask,感兴趣的朋友一起看看吧
    2023-02-02
  • C语言的各类变量和零值的比较详解

    C语言的各类变量和零值的比较详解

    这篇文章主要为大家介绍了C语言的各类变量和零值的比较,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-11-11
  • C++数据结构之实现邻接表与邻接矩阵的相互转换

    C++数据结构之实现邻接表与邻接矩阵的相互转换

    这篇文章主要为大家学习介绍了C++如何实现邻接表与邻接矩阵的相互转换,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-07-07
  • C语言学习之指针知识总结

    C语言学习之指针知识总结

    想突破C语言的学习,对指针的掌握是非常重要的,本文为大家总结了C语言中指针的相关知识点,文中的示例代码讲解详细,感兴趣的可以学习一下
    2022-07-07
  • C++设计模式编程中简单工厂与工厂方法模式的实例对比

    C++设计模式编程中简单工厂与工厂方法模式的实例对比

    这篇文章主要介绍了C++设计模式编程中简单工厂与工厂方法模式的实例对比,文中最后对两种模式的优缺点总结也比较详细,需要的朋友可以参考下
    2016-03-03
  • C/C++堆区专篇精讲

    C/C++堆区专篇精讲

    一直以来总是对这个问题的认识比较朦胧,我相信很多朋友也是这样的,总是听到内存一会在栈上分配,一会又在堆上分配,那么它们之间到底是怎么的区别呢,让我们一起来看看
    2022-10-10

最新评论