C++(十二)优先级队列 Priority_queue

一、概念

  std::priority_queue 是 C++ 标准模板库(STL)中的一种适配器容器,用于实现优先队列数据结构。与普通的 std::queue 不同,std::priority_queue 中的元素会根据优先级排序,优先级最高的元素总是位于队列的前端(即可以通过 top() 函数访问到)。

        这是通过使用堆(通常是大堆)来实现的。 

通过上面的陈述可以了解到:进入priority_queue的数据会按一定规则——优先级排序。

那这是按照什么规则排序的呢? 

  • priority_queue 内部使用的是一种特殊的二叉树结构完全二叉树的结构,排序:大堆或者小堆(默认的大堆)

  • 大堆:每个节点的值都大于或等于其子节点的值(根节点是最大值)
  • 小堆:每个节点的值都小于或等于其子节点的值(根节点是最小值)

         因为二叉树是一个比较复杂且巧妙的内容,如果仔细介绍需要花费很大的篇幅,这里只是简单的一笔带过,想要了解更多的关于二叉树大堆小堆,建堆规则,向上调整向下调整等知识建议先系统学习数据结构:树部分。

priority_queue中的 top() 会是数值最大值或者最小值(大堆堆顶是最大值,小堆堆顶是最小值)

二、使用 

  了解priority_queue的底层结构之后,priority_queue的使用非常的简单!!

2.2 priority_queue类模板定义

priority_queue类的模板相较于queue是更复杂一点的,也是我们学习的难点:(源定义)

template<
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>
> 
class priority_queue{
 ... ... 
}

上面的源码中类模板给了缺省值:默认容器是vector,默认生成的是大堆 

注意:Compare = less<>  是大堆

我们一点一看:先去掉缺省值:

//template<class T,class Container,class Compare > 
template<
    class T,
    class Container,
    class Compare > 
class priority_queue{
 ... ... 
}

这个还是容易理解:

  • T:数据类型 
  • Containter(容器):使用什么容器,(结合缺省值来看:默认容器是vector<T>)
  • Compare(比较):建大堆还是小队

当这个理解之后我们来看看Compare的缺省值是什么?

template<
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>
> 

std::less 是一个标准库中的模板类,它实现了一个简单的比较函数,用于判断左操作数是否小于右操作数:

template <typename T>
struct less {
    constexpr bool operator()(const T& left, const T& right) const {
        return left < right;
    }
};

 但是它在less<>里面的Container::value_type又是什么意思呢?

class Compare = std::less<typename Container::value_type>

Container::value_type:这个类型定义是所有标准容器的成员类型,用于指代前面容器存储的元素类型。例如,对于 std::vector<int>Container::value_type 就是 int。 

由于有些复杂这里通过图形帮大家更直观的理解:

下面再结合代码来看这部分内容:

假设这里定义了一个priority_queue对象 pq:

std::priority_queue<int> pq;

在这个例子中,std::priority_queue 实际上等价于: 

std::priority_queue<int, std::vector<int>, std::less<int>> pq;

 只不过前面用了缺省值,下面显示模板实例化。

大堆的简单使用:

#include <iostream>
#include <queue>
#include <vector>

int main() {
    std::priority_queue<int> maxHeap;//使用缺省,默认vector默认less(大堆)

    maxHeap.push(10);//插入一些无序的值
    maxHeap.push(20);//数据,数据会根据大堆的规则自动排序
    maxHeap.push(5);
    maxHeap.push(70);
    maxHeap.push(56);

    //打印堆顶元素
    std::cout << "堆顶 : " << maxHeap.top() << std::endl;  

    maxHeap.pop();       //删除一个元素之后打印
    std::cout << "删除一个元素,堆顶: " << maxHeap.top() << std::endl;  

    std::cout << "maxHeap: " << std::endl;
    //打印并删除
    while (!maxHeap.empty()) {
        std::cout << maxHeap.top() << " ";
        maxHeap.pop();
    }

    return 0;
}

 运行结果:

堆顶 : 70
删除一个元素,堆顶: 56
maxHeap: 56 20 10 5

当理解了大堆之后,以下是一个建小堆的示例: 

注意:小堆必须显示模板实例化,通过显式传递 std::greater<T> 作为 Compare 参数。

#include <iostream>
#include <queue>
#include <vector>

int main() {
    // 使用 std::greater<int> 创建最小堆
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;

    minHeap.push(10);//插入一些无序的值
    minHeap.push(20);
    minHeap.push(5);
    minHeap.push(70);
    minHeap.push(56);

    std::cout << "小堆 Top: " << minHeap.top() << std::endl;  // 输出 5

    minHeap.pop();
    std::cout << "删除一个元素后,小堆 Top: " << minHeap.top() << std::endl;  // 输出 10

    return 0;
}

std::greater<T> 作为 Compare 参数和std::less<T>的用法一摸一样。 

  • Compare<greater<T> >建小堆
  • Compare<less<T> >建大堆

最后:priority_queue不支持使用list容器!!

    priority_queue不支持使用list容器!!

    priority_queue不支持使用list容器!!

priority_queue不支持的容器包括那些不提供随机访问迭代器或者不支持 push_backpop_back 操作的容器,list 只支持双向迭代器,不支持随机访问,所以不能用作 std::priority_queue 的底层容器。

2.1 priority_queue接口

  • empty():检查队列是否为空。
  • size():返回队列中的元素数量。
  • top():返回堆顶(根节点)的元素。
  • push(const T& value):将元素插入优先队列中。
  • pop():移除优先级最高的元素。
  • swap():交换两个优先队列的内容。

        接口函数的使用非常的简单,构造函数在这里没有详细讨论,因为和queue的构造函数用法一样。其余接口函数与适配器stack和queue相似度很高,所以我们直接看使用。

示例

        一个示例使用 deque 作为底层容器的 priority_queue ,并将它配置为小堆,结合了大部分常用接口函数的使用。(仅参考)

#include <iostream>
#include <queue>
#include <deque>
#include <functional> // 使用 std::greater需要的头文件

int main() {
    // 使用 std::deque 作为底层容器,std::greater<int> 作为比较器,创建一个小堆
    std::priority_queue<int, std::deque<int>, std::greater<int>> minHeap;

    // 向堆中添加元素
    minHeap.push(30);
    minHeap.push(10);
    minHeap.push(20);
    minHeap.push(5);
    minHeap.push(15);
    minHeap.push(80);
    minHeap.push(27);
    minHeap.push(67);

    // 打印堆顶元素 (最小元素)
    std::cout << "堆顶: " << minHeap.top() << std::endl;

    // 检查堆是否为空
    if (!minHeap.empty()) {
        std::cout << "堆不为空." << std::endl;
    }

    // 打印堆的大小
    std::cout << "堆的大小: " << minHeap.size() << std::endl;

    // 打印并移除所有元素
    std::cout << "打印并移除所有元素:" << std::endl;
    while (!minHeap.empty()) {
        std::cout << minHeap.top() << " "; // 打印堆顶元素
        minHeap.pop(); // 移除堆顶元素
    }
    std::cout << std::endl;

    // 重新插入元素,展示 swap 函数
    minHeap.push(100);
    minHeap.push(50);

    std::cout << "清除后重新插入:" << std::endl;
    std::cout << "堆顶: " << minHeap.top() << std::endl;

    // 创建另一个堆
    std::priority_queue<int, std::deque<int>, std::greater<int>> anotherHeap;
    anotherHeap.push(70);
    anotherHeap.push(60);

    // 交换两个堆
    minHeap.swap(anotherHeap);

    // 交换后的堆顶元素
    std::cout << "交换后的堆顶元素: " << minHeap.top() << std::endl;

    return 0;
}

 运行结果:

堆顶: 5
堆不为空.
堆的大小: 8
打印并移除所有元素:
5 10 15 20 27 30 67 80
清除后重新插入:
堆顶: 50
交换后的堆顶元素: 60

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值