当前位置:首页 » 《我的小黑屋》 » 正文

【C++】优先级队列

20 人参与  2024年09月23日 08:41  分类 : 《我的小黑屋》  评论

点击全文阅读


一. 优先级队列简介

        首先,它的本质就是一个堆(heap)。

在C++中,优先级队列(Priority Queue)是一种特殊的容器适配器,它提供了一个能实现类似堆的结构的功能。优先级队列保证了队首元素总是最大的(或者在最小的元素在优先级最高的定义下是最小的),与普通队列不同,优先级队列的出队操作(front和pop)总是取出具有最高优先级的元素,而入队操作(push)会将新元素插入到正确的位置以保持优先级顺序。这种顺序是通过堆这种数据结构来实现的。

在实践中,优先级队列通常用于需要快速检索最大(或最小)元素的场景,例如在图算法中的Dijkstra算法,或者在处理事件时根据事件的优先级来排序。

二. 使用示例

在C++标准库中,优先级队列(std::priority_queue)是在<queue>头文件中定义的。它有以下几个基本操作:

empty():判断优先级队列是否为空。size():返回优先级队列中元素的数量。top():返回队首元素,即优先级最高的元素。push(const T& value):向优先级队列中添加一个元素,并自动根据优先级排序。pop():移除并返回队首元素(优先级最高的元素)。

在使用它时要注意,它默认使用 std::less 作为比较函数,这意味着它默认构建的是最大堆。如果你想创建一个最小堆,你可以在创建优先级队列时提供一个不同的比较函数,比如 std::greater


下面是一个简单的例子,展示了如何在C++中使用优先级队列:

#include <iostream>#include <queue>int main() {    std::priority_queue<int> pq; // 默认创建最大堆    pq.push(1);    pq.push(2);    pq.push(3);    pq.push(4);    pq.push(5);    while (!pq.empty()) {        std::cout << pq.top() << " "; // 输出:5 4 3 2 1        pq.pop();    }    return 0;}

创建它时,还可以指定底层元素类型,容器类型(默认为std::vector)以及可选的比较对象。

比如下面的最小堆:

#include <iostream>#include <queue>int main() {    std::priority_queue<int, std::vector<int>, std::greater<int>> pq; // 创建最小堆    pq.push(5);    pq.push(4);    pq.push(3);    pq.push(2);    pq.push(1);    while (!pq.empty()) {        std::cout << pq.top() << " "; // 输出:1 2 3 4 5        pq.pop();    }    return 0;}

这样就改变了队列的优先级。

三. 模拟实现 priority_queue

因为优先级队列的底层和  的实现逻辑相同,所以得先实现向上调整算法,和向下调整算法,这里因为要适配优先级队列,所以会稍微有点差别。这里建的是一个大顶堆

1.堆的写法应该是这样:

// 大顶堆// 向上调整void adjust_up(size_t child) {    size_t parent = (child - 1) / 2;    while (child > 0) {        if (arr[parent] > arr[child]) {            swap(c[parent], c[child]);            child = parent;            parent = (parent - 1) / 2;        }        else            break;    }}// 向下调整void adjust_down(size_t parent) {    size_t child = parent * 2 + 1;    while (child < c.size()) {        if (child + 1 < c.size() && arr[child] > arr[child+1])            child++;        if (arr[parent] > arr[child]) {            swap(c[parent], c[child]);            parent = child;            child = child * 2 + 1;        }        else            break;    }}

而在优先级队列中是这样写的:

template<class T>struct Greater {    bool operator()(const T& x, const T& y) {        return x > y;    }};template<class T>struct Less{    bool operator()(const T& x, const T& y) {        return x < y;    }};template <class T, class Container = vector<T>, class Compare = less<T> >class priority_queue{public:    void adjust_up(size_t child) {        size_t parent = (child - 1) / 2;        while (child > 0) {            if (comp(c[parent], c[child])) {                swap(c[parent], c[child]);                child = parent;                parent = (parent - 1) / 2;            }            else                break;        }    }    void adjust_down(size_t parent) {        size_t child = parent * 2 + 1;        while (child < c.size()) {            if (child + 1 < c.size() && comp(c[child], c[child + 1]))                child++;            if (comp(c[parent], c[child])) {                swap(c[parent], c[child]);                parent = child;                child = child * 2 + 1;            }            else                break;        }    }    // ......private:    Container c;    Compare comp;};

可以看到这里因为有两个优先级,所以用到了两个重载了 ( ) 操作符的仿函数,使其可以像函数一样被调用,这一点很像C语言中的函数调用。

完整实现代码

#include<vector>using namespace std;namespace pq{    template<class T>    struct Greater     {        bool operator()(const T& x, const T& y) {            return x > y;        }    };    template<class T>    struct Less    {        bool operator()(const T& x, const T& y) {            return x < y;        }    };    // 默认建大顶堆    template <class T, class Container = vector<T>, class Compare = less<T> >    class priority_queue    {    public:        priority_queue(){}        void adjust_up(size_t child) {            size_t parent = (child - 1) / 2;            while (child > 0) {                if (comp(c[parent], c[child])) {                    swap(c[parent], c[child]);                    child = parent;                    parent = (parent - 1) / 2;                }                else                    break;            }        }        void adjust_down(size_t parent) {            size_t child = parent * 2 + 1;            while (child < c.size()) {                if (child + 1 < c.size() && comp(c[child], c[child + 1]))                    child++;                if (comp(c[parent], c[child])) {                    swap(c[parent], c[child]);                    parent = child;                    child = child * 2 + 1;                }                else                    break;            }        }        bool empty() const {            return c.empty();        }        size_t size() const {            return c.size();        }        T& top() const {            if (empty())                return;            return c[0];        }        void push(const T& x) {            c.push_back(x);            adjust_up(c.size() - 1);        }        void pop() {            if (empty())                return;            swap(c[0], c[c.size() - 1]);            c.pop_back();            adjust_down(0);        }    private:        Container c;        Compare comp;    };}


点击全文阅读


本文链接:http://zhangshiyu.com/post/163252.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1