STL源码剖析 priority_queue

本文详细介绍了C++中的优先级队列(priority_queue),它是一个基于最大堆的数据结构,用于存储具有权重的元素。元素根据其权重进行排序,权值最高的元素优先出队。priority_queue不提供迭代器,但提供了如empty、size、top、push和pop等操作。示例代码展示了如何创建和使用priority_queue,以及其内部如何通过泛型算法调整堆的结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • priority_queue是一个拥有权重概念的queue,允许底部加入新的元素,头部删除旧的元素,以及审视元素数值的操作
  • priority_queue带有权重的概念,即元素按照权重进行排列,而不是按照插入队列的顺序进行排序。要求权值高者在前
  • 缺省情况下,priority_queue使用max_heap完成,而max_heap物理层面是基于vector逻辑层面表现像complate binary tree;max_tree用于实现priority_queue的按照权值高低自动递增排序的特性

priority_queue定义完整列表

  • priority_queue底层使用vector,在加上堆的处理规则
  • priority_queue不被归纳为容器 而是容器适配器
#include <iostream>
#include <vector>

#ifdef __STL_USE_EXCEPTIONS
#define __STL_TRY   try
#define __STL_UNWIND(action)   catch(...) { action; throw; }
#else
#define __STL_TRY
#define __STL_UNWIND(action)
#endif


template <class T,class Sequence = std::vector<T>,
          class Compare = std::less<typename Sequence::value_type>>
class priority_queue{
public:
    typedef typename Sequence::valuetype value_type;
    typedef typename Sequence::size_type size_type;
    typedef typename Sequence::reference reference;
    typedef typename Sequence::const_reference const_reference;
protected:
    Sequence c; //底层容器
    Compare comp; //元素大小的比较标准
public:
    priority_queue() : c (){}
    explicit priority_queue(const Compare& x) : c() ,comp(x){}
    //以下使用的make_heap()、push_heap()、pop_heap()都是泛型算法
    //注意 任意一个构造函数都立刻在底层容器内产生一个implicit representation heap
    //指代比较器
    template<class InputIterator>
    priority_queue(InputIterator first, InputIterator last,const Compare& x):
    c(first,last),comp(x){
        std::make_heap(c.begin(),c.end(),comp);
    }
    //没有指代比较器
    template<class InputIterator>
    priority_queue(InputIterator first, InputIterator last):
            c(first,last){
        std::make_heap(c.begin(),c.end(),comp);
    }
    bool empty()const{
        return c.empty();
    }
    size_type size() const{
        return c.size();
    }
    const_reference top()const{
        return c.front();
    }
    void push(const value_type& x){
        __STL_TRY{
            //push_heap 是泛型算法,先利用底层的push_back()将新的元素推入末端,再重新排列heap
            c.push_back(x);
            //push_heap 是泛型算法
            std::push_heap(c.begin(),c.end(),comp);
        }
        __STL_UNWIND(c.clear());
    }
    void pop(){
        __STL_TRY{
            //pop_heap是泛型算法,从heap中取出一个元素,并不是整整将这个元素弹出,而是重排heap
            //需要使用底层vector的pop_back()取得被弹出的元素
            std::pop_heap(c.begin(),c.end(),comp);
            c.pop_back();
        }
        __STL_UNWIND(c.clear());
    }


};

priority_queue没有迭代器

  • priority_queue的所有元素进出是有规则限制的,只有queue的顶端元素(权值最高者)才可以被外界使用
  • priority_queue不提供遍历的功能,因此无迭代器

测试用例

#include <iostream>
#include <vector>

#ifdef __STL_USE_EXCEPTIONS
#define __STL_TRY   try
#define __STL_UNWIND(action)   catch(...) { action; throw; }
#else
#define __STL_TRY
#define __STL_UNWIND(action)
#endif


template <class T,class Sequence = std::vector<T>,
          class Compare = std::less<typename Sequence::value_type>>
class priority_queue{
public:
    typedef typename Sequence::value_type value_type;
    typedef typename Sequence::size_type size_type;
    typedef typename Sequence::reference reference;
    typedef typename Sequence::const_reference const_reference;
protected:
    Sequence c; //底层容器
    Compare comp; //元素大小的比较标准
public:
    priority_queue() : c (){}
    explicit priority_queue(const Compare& x) : c() ,comp(x){}
    //以下使用的make_heap()、push_heap()、pop_heap()都是泛型算法
    //注意 任意一个构造函数都立刻在底层容器内产生一个implicit representation heap
    //指代比较器
    template<class InputIterator>
    priority_queue(InputIterator first, InputIterator last,const Compare& x):
    c(first,last),comp(x){
        std::make_heap(c.begin(),c.end(),comp);
    }
    //没有指代比较器
    template<class InputIterator>
    priority_queue(InputIterator first, InputIterator last):
            c(first,last){
        std::make_heap(c.begin(),c.end(),comp);
    }
    bool empty()const{
        return c.empty();
    }
    size_type size() const{
        return c.size();
    }
    const_reference top()const{
        return c.front();
    }
    void push(const value_type& x){
        __STL_TRY{
            //push_heap 是泛型算法,先利用底层的push_back()将新的元素推入末端,再重新排列heap
            c.push_back(x);
            //push_heap 是泛型算法
            std::push_heap(c.begin(),c.end(),comp);
        }
        __STL_UNWIND(c.clear());
    }
    void pop(){
        __STL_TRY{
            //pop_heap是泛型算法,从heap中取出一个元素,并不是整整将这个元素弹出,而是重排heap
            //需要使用底层vector的pop_back()取得被弹出的元素
            std::pop_heap(c.begin(),c.end(),comp);
            c.pop_back();
        }
        __STL_UNWIND(c.clear());
    }
};

int main(){
    int ia[9] = {0,1,2,3,4,8,9,3,5};
    priority_queue<int>iqp(ia,ia+9);
    std::cout << iqp.size() << std::endl; //9

    for (int i = 0; i < iqp.size(); ++i) {
        std::cout << iqp.top() << ' '; //9 9 9 9 9 9 9 9 9
    }
    std::cout << std::endl;

    while(!iqp.empty()){
        std::cout << iqp.top() << ' '; //9 8 5 4 3 3 2 1 0
        iqp.pop();
    }
    std::cout << std::endl;
}

参考链接

### 一、queuepriority_queue 的定义 `queue` 是一种 FIFO(First In First Out,先进先出)的线性数据结构[^4]。这意味着最早进入队列的元素会最先被移除。 而 `priority_queue` 则是一种基于堆的数据结构,其核心特点是:无论何时插入新元素,队列头部总是具有最高优先级的元素[^1]。默认情况下,`priority_queue` 使用最大堆来实现,因此顶部元素是当前队列中最大的值。 --- ### 二、queuepriority_queue 的主要区别 #### 1. 数据存取逻辑 - **Queue**: 遵循严格的 FIFO 原则,即最先进入队列的元素会被最先取出。 - **Priority Queue**: 不遵循 FIFO 原则,而是依据元素的优先级决定哪个元素应被最先取出。通常来说,优先级最高的元素会在队首位置[^4]。 #### 2. 底层实现机制 - **Queue**: 默认使用双端队列 (`deque`) 实现,支持两端操作 (front 和 back)[^4]。 - **Priority Queue**: 默认使用向量 (`vector`) 结合堆算法实现,底层是一个完全二叉树表示的最大堆或最小堆[^3]。 #### 3. 插入与删除效率 - 对于普通的 `queue`,插入和删除的时间复杂度均为 O(1),因为只需要调整队尾或队头指针即可完成相应操作。 - 而对于 `priority_queue`,由于每次都需要维护堆性质,插入时间为 O(log n),弹出同样为 O(log n) 时间复杂度[^5]。 #### 4. 自定义比较函数的支持程度 - **Queue**: 不允许自定义排序规则,仅能按固定顺序依次进出。 - **Priority Queue**: 支持通过模板参数传递自定义比较器(如 `std::greater<T>` 或其他用户定义的谓词类),从而灵活改变优先级判断标准[^5]。 --- ### 三、queuepriority_queue 的典应用场景 #### 1. Queue 的适用场景 当需要严格按照时间序列处理任务或者消息时可以考虑使用普通队列。例如: - CPU调度中的轮转法(Round Robin Scheduling) - 广度优先搜索(BFS) ```cpp #include <iostream> #include <queue> using namespace std; void demoQueue() { queue<int> q; q.push(1); q.push(2); cout << "Front item: " << q.front() << endl; // 输出 Front item: 1 q.pop(); cout << "After pop, front item: " << q.front() << endl; // After pop, front item: 2 } ``` #### 2. Priority Queue 的适用场景 如果希望根据某些特定条件动态安排待办事项,则更适合选用带权重管理功能的优先权队列。比如: - Dijkstra算法求解单源最短路径问题; - Huffman编码构建最优前缀码表过程等等。 下面展示了一个简单的例子演示如何利用 C++ STL 提供的功能创建一个小顶堆: ```cpp #include <functional> #include <queue> #include <vector> #include <iostream> using namespace std; void demoPriorityQueue(){ vector<int> nums = {2, 9, 1, 6, 7, 4 ,0}; priority_queue<int,vector<int>,greater<int>> minHeap(nums.begin(),nums.end()); while(!minHeap.empty()){ cout<<minHeap.top()<<" "; minHeap.pop(); } } // Output will be : 0 1 2 4 6 7 9 ``` --- ### 四、总结对比表格 | 特性 | Queue | Priority Queue | |---------------------|----------------------------------|------------------------------------| | 存储模 | FIFO | 根据优先级 | | 底层实现 | deque | vector | | 插入/删除复杂度 | O(1)/O(1) | O(log N)/O(log N) | | 是否可定制排序 | 否 | 可 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值