STL详解 - priority_queue

目录

一、priority_queue 是什么

二、priority_queue 的底层实现

三、priority_queue 的定义方式

四、priority_queue 的成员函数

五、priority_queue 使用示例

六、priority_queue 的自定义比较方式

七、priority_queue 的模拟实现


一、priority_queue 是什么

  • priority_queue 是一种容器适配器,它的核心特性是:队列中第一个元素始终是队列中最大的元素(默认情况下)。这使得 priority_queue 在处理需要按照优先级排序的数据时非常高效。
  • 例如,在任务调度系统中,优先级高的任务应该先被执行;在模拟场景中,事件按照时间顺序处理。这些场景都可以通过 priority_queue 来实现。

二、priority_queue 的底层实现

priority_queue 默认使用 vector 作为底层存储容器,并通过堆算法将元素组织成堆结构。堆是一种特殊的树状结构,分为大顶堆和小顶堆:

  • 大顶堆 :父节点的值大于或等于子节点的值,priority_queue 默认构造的是大顶堆

  • 小顶堆 :父节点的值小于或等于子节点的值。

三、priority_queue 的定义方式

1. 使用 vector 作为底层容器,构造大顶堆

priority_queue<int, vector<int>, less<int>> q1;
  • 这里明确指定了底层容器为 vector,比较方式为 less<int>,即元素按照从小到大的顺序比较,构造出大顶堆。

2. 使用 vector 作为底层容器,构造小顶堆

priority_queue<int, vector<int>, greater<int>> q2;
  • 此时比较方式为 greater<int>,元素按照从大到小的顺序比较,构造出小顶堆。

3. 默认定义

priority_queue<int> q3;
  • 这是最简洁的定义方式。此时底层容器默认为 vector,比较方式默认为 less<int>,即构造大顶堆。

四、priority_queue 的成员函数

方法功能描述时间复杂度
push(x)插入元素并重新排序O(logN)
pop()删除堆顶元素O(logN)
top()访问堆顶元素O(1)
empty()判断队列是否为空O(1)
size()获取元素数量O(1)

1. push:插入元素

将元素插入到 priority_queue 中,并自动调整堆结构以维护优先级关系。

q.push(10);
q.push(5);
q.push(15);

插入元素后,堆会自动调整,大顶堆的堆顶始终是最大元素。

2. pop:删除堆顶元素

移除 priority_queue 中的最大元素(大顶堆)或最小元素(小顶堆),并调整堆结构。

q.pop();

执行 pop 操作后,堆顶元素被删除,堆结构重新调整以维护优先级关系。

3. top:访问堆顶元素

返回 priority_queue 中的最大元素(大顶堆)或最小元素(小顶堆),但不删除该元素。

int maxElement = q.top(); // 对于大顶堆,获取最大元素

4. size:获取队列中元素个数

返回 priority_queue 中当前有效的元素数量。

size_t count = q.size();

5. empty:判断队列是否为空

检测 priority_queue 是否为空,若为空返回 true,否则返回 false

if (q.empty()) 
{
    cout << "队列为空" << endl;
} 
else 
{
    cout << "队列不为空" << endl;
}

6. swap:交换两个队列的内容

交换两个 priority_queue 的元素内容。

priority_queue<int> q1, q2;

// ... 向 q1 和 q2 中添加元素 ...

q1.swap(q2);

五、priority_queue 使用示例

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

int main() 
{
    priority_queue<int> q;

    // 向队列中添加元素
    q.push(3);
    q.push(1);
    q.push(4);
    q.push(2);
    q.push(5);

    // 输出队列中的元素
    cout << "队列中的元素按优先级顺序排列:" << endl;
    while (!q.empty()) 
    {
        cout << q.top() << " "; // 输出堆顶元素
        q.pop(); // 删除堆顶元素
    }
    cout << endl;

    return 0;
}

从输出结果可以看出,元素按照从大到小的顺序输出,符合大顶堆的特点。

六、priority_queue 的自定义比较方式

除了使用默认的大顶堆和小顶堆,我们还可以自定义比较方式,以满足特定的需求。

例如,假设我们有一个 Student 类,我们希望按照学生的成绩来构造 priority_queue

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

class Student 
{
public:
    string name;
    int score;

    Student(string n, int s) 
        : name(n)
        , score(s) 
    {}

    // 重载 < 运算符,用于比较两个学生对象
    bool operator<(const Student& other) const 
    {
        return score < other.score; // 按成绩从高到低排序
    }
};

int main() 
{
    priority_queue<Student> students;

    students.push(Student("Alice", 90));
    students.push(Student("Bob", 80));
    students.push(Student("Charlie", 95));

    // 输出学生信息,按成绩从高到低排列
    cout << "学生按成绩从高到低排列:" << endl;
    while (!students.empty()) 
    {
        cout << students.top().name << ": " << students.top().score << endl;
        students.pop();
    }

    return 0;
}

在这个例子中,我们通过重载 Student 类的 < 运算符,自定义了比较方式,使得 priority_queue 按照学生的成绩从高到低排序。

七、priority_queue 的模拟实现

#pragma once

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

namespace lv // 防止命名冲突
{
    // 大顶堆比较器(默认)
    template<class T>
    struct less 
    {
        bool operator()(const T& x, const T& y) const 
        {
            return x < y; // 父节点小于子节点时交换
        }
    };

    // 小顶堆比较器
    template<class T>
    struct greater 
    {
        bool operator()(const T& x, const T& y) const 
        {
            return x > y; // 父节点大于子节点时交换
        }
    };

    // 优先级队列模板类
    template<class T, class Container = std::vector<T>, class Compare = less<T>>
    class priority_queue
    {
    public:
        // 默认构造函数
        priority_queue() = default;

        // 通过迭代器范围构造
        template <class InputIterator>
        priority_queue(InputIterator first, InputIterator last, const Compare& comp = Compare())
            : _con(first, last)
            , _comp(comp)
        {
            // 从最后一个非叶子节点开始建堆
            for (int i = (_con.size() - 1) / 2; i >= 0; --i) 
            {
                AdjustDown(_con.size(), i);
            }
        }

        // 插入元素
        void push(const T& x) 
        {
            _con.push_back(x);          // 插入尾部
            AdjustUp(_con.size() - 1);  // 向上调整
        }

        // 删除堆顶
        void pop() {
            if (empty()) return;         // 空队列处理
            std::swap(_con[0], _con.back()); // 交换首尾
            _con.pop_back();            // 删除尾部
            AdjustDown(_con.size(), 0); // 向下调整
        }

        // 访问堆顶
        T& top() 
        { 
            return _con.front(); 
        
        }
        const T& top() const 
        {
            return _con.front(); 
        }

        // 容量操作
        size_t size() const 
        {
            return _con.size(); 
        }

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

    private:
        Container _con;    // 底层容器
        Compare _comp;     // 比较器

        // 向上调整(插入时使用)
        void AdjustUp(int child) 
        {
            while (child > 0) 
            {
                int parent = (child - 1) / 2;
                if (_comp(_con[parent], _con[child])) 
                { // 比较父子节点
                    std::swap(_con[parent], _con[child]);
                    child = parent;
                }
                else 
                {
                    break; // 堆结构已满足
                }
            }
        }

        // 向下调整(删除时使用)
        void AdjustDown(int heapSize, int parent) 
        {
            int child = 2 * parent + 1; // 左子节点
            while (child < heapSize) 
            {
                // 选择更大的子节点
                if (child + 1 < heapSize && _comp(_con[child], _con[child + 1])) 
                {
                    ++child;
                }
                // 比较父子节点
                if (_comp(_con[parent], _con[child])) 
                {
                    std::swap(_con[parent], _con[child]);
                    parent = child;
                    child = 2 * parent + 1;
                }
                else 
                {
                    break; // 堆结构已满足
                }
            }
        }
    };      
} 

测试代码:

// 测试代码
#include "priority_queue.h"

int main()
{
    lv::priority_queue<int> pq;

    pq.push(10);
    pq.push(5);
    pq.push(15);
    pq.push(7);
    pq.push(20);

    cout << "priority_queue elements (top to bottom):" << endl;
    while (!pq.empty())
    {
        cout << pq.top() << " ";
        pq.pop();
    }
    cout << endl;

    // 测试小顶堆
    lv::priority_queue<int, vector<int>, greater<int>> min_pq;
    min_pq.push(10);
    min_pq.push(5);
    min_pq.push(15);
    min_pq.push(7);
    min_pq.push(20);

    cout << "min_pq elements (top to bottom):" << endl;
    while (!min_pq.empty())
    {
        cout << min_pq.top() << " ";
        min_pq.pop();
    }
    cout << endl;

    return 0;
}

输出结果为:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南风与鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值