priority_queue

  • 定义
  • 如何实现自定义Comp类
    • priority_queue::push()
      • push_heap()
      • _Push_heap_by_index() [核心代码]
    • 自定义Comp类

定义

// https://github.com/microsoft/STL/blob/main/stl/inc/queue
// CLASS TEMPLATE priority_queue
template <class _Ty, class _Container = vector<_Ty>, class _Pr = less<typename _Container::value_type>>
class priority_queue {public:/* ...... */priority_queue() = default;                 // 默认构造函数explicit priority_queue(const _Pr& _Pred) noexcept(is_nothrow_default_constructible_v<_Container>&& is_nothrow_copy_constructible_v<value_compare>) // strengthened: c(), comp(_Pred) {}/* ...... */
protected:_Container c{};_Pr comp{};
};
  • _Container : 表示底层容器,默认为vector。(priority_queue是一种配接器。)
  • _Pr : 表示比较类,默认为仿函式less,因此priority_queue默认为最大堆。

如何实现自定义Comp类

想要自己定义优先队列中元素之间的优先级,需要实现自定义的Comp类,即定义中的_Pr。
我们从push()函数入手,观察priority_queue是如何根据Comp类计算元素之间的优先级的。

priority_queue::push()

// https://github.com/microsoft/STL/blob/main/stl/inc/queue
void push(const value_type& _Val) {c.push_back(_Val);_STD push_heap(c.begin(), c.end(), comp);
}

priority_queue::push是借助push_heap实现的。先把插入元素放置在容器尾部,然后通过push_heap将插入元素调整至合适位置。

push_heap()

// https://github.com/microsoft/STL/blob/main/stl/inc/algorithm
// FUNCTION TEMPLATE push_heaptemplate <class _RanIt, class _Pr>
_CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) {// push *(_Last - 1) onto heap at [_First, _Last - 1)/* ...... */if (2 <= _Count) {_Iter_value_t<_RanIt> _Val = _STD move(*--_ULast);_Push_heap_by_index(_UFirst, --_Count, _Diff(0), _STD move(_Val), _Pass_fn(_Pred));}
}

当容器内的元素数量大于等于2时,调用_Push_heap_by_index()调整插入元素的位置。

_Push_heap_by_index() [核心代码]

template <class _RanIt, class _Ty, class _Pr>
_CONSTEXPR20 void _Push_heap_by_index(_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Top, _Ty&& _Val, _Pr _Pred) {// percolate _Hole to _Top or where _Val belongsusing _Diff = _Iter_diff_t<_RanIt>;for (_Diff _Idx = (_Hole - 1) >> 1; // shift for codegen_Top < _Hole && _DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val); //_Idx = (_Hole - 1) >> 1) { // shift for codegen// move _Hole up to parent*(_First + _Hole) = _STD move(*(_First + _Idx));_Hole             = _Idx;}*(_First + _Hole) = _STD forward<_Ty>(_Val); // drop _Val into final hole
}

其中

// https://github.com/microsoft/STL/blob/main/stl/inc/xutility
#if _ITERATOR_DEBUG_LEVEL < 2
#define _DEBUG_LT_PRED(pred, x, y) static_cast<bool>(pred(x, y))
......
  • _Pred:一个 Comp (即_Pr)类的实例
  • _Val: 插入元素
  • _Hole:插入元素当前位置 (偏移值)
  • _Idx:插入元素当前的父亲节点的位置 (偏移值)
  • _Top:根节点的位置 (偏移值)
  • _First:起始迭代器,加上偏移值即为对应元素的迭代器。

使用到_Pred的语句只有一句,即_DEBUG_LT_PRED(_Pred, *(_First + _Idx), _Val),其中*(_First+_Idx)表示当前的父亲元素。

  • 当返回true时,执行循环语句,交换插入元素与当前父亲元素的位置,插入元素向根移动,即插入元素的优先级更高。
  • 当返回false时,跳出循环,插入元素的移动停止,确定位置。

自定义Comp类

据此我们可以总结自定义Comp类的写法。

  1. 自定义Comp是类,即class或struct。
  2. 自定义Comp类重载了"()"操作符。
  3. comp(lhs, rhs)返回true时, rhs优先级高。(返回false时,lhs优先级高。)
struct Comp {bool operator() (const T &lhs, const T &rhs) { return lhs.val < rhs.val; }
}
priority_queue<T, vector<T>, Comp> myheap;

另外对于定义了<>操作符的类型,大根堆可以使用less仿函式,小根堆可以使用greater仿函式。

priority_queue<T> max_heap;                                // '<'有定义时, 表示大根堆
priority_queue<T, vector<T>, greater<T>> min_heap;        // '>'有定义时, 表示小根堆

priority_queue 自定义Comp类相关推荐

  1. 什么是php model类,thinkphp的自定义model类有什么作用?

    请问,thinkphp的自定义model类有什么作用?如: <?php //自定义Modle类 namespace Home\Model; use Think\Model; class StuM ...

  2. 掌握 ASP.NET 之路:自定义实体类简介

    发布日期 : 5/24/2005| 更新日期 : 5/24/2005 Karl Seguin Microsoft Corporation 摘要:有些情况下,非类型化的 DataSet 可能并非数据操作 ...

  3. 自定义模板类(循环队列)

    自定义模板类--循环链表 正做的这个链表的时候,遇到了,对于友元函数的处理问题 实现代码如下(配有测试main): #include <iostream> using namespace ...

  4. 13.6 Thread类自定义线程类

    package cn.chen.thread; /** * 线程:* 多线程:* 一个java程序只是有两个线程:* 一个是主线程负责main方法代码执行,一个是垃圾回收器线程,负责* 创建线程的方式 ...

  5. Qt中的自定义模型类

    文章目录 1 Qt中的通用模型类 1.1 Qt中的通用模型类 1.2 Qt中的变体类型QVariant 2 自定义模型类 2.1 自定义模型类设计分析 2.2 自定义模型类数据层.数据表示层.数据组织 ...

  6. RocketMQ-初体验RocketMQ(11)-过滤消息_自定义Java类筛选消息

    文章目录 概述 集群信息 项目结构 生产者 自定义类 消费者 测试结果 概述 RocketMQ-初体验RocketMQ(10)-过滤消息_SQL92表达式筛选消息 通过SQL92的方式,消费者可以过滤 ...

  7. java kafka 设置分区_Java kafka如何实现自定义分区类和拦截器

    Java kafka如何实现自定义分区类和拦截器 2.producer配置文件指定,具体的分区类 // 具体的分区类 props.put(ProducerConfig.PARTITIONER_CLAS ...

  8. DL之NN:基于(sklearn自带手写数字图片识别数据集)+自定义NN类(三层64→100→10)实现97.5%准确率

    DL之NN:基于(sklearn自带手写数字图片识别数据集)+自定义NN类(三层64→100→10)实现97.5%准确率 目录 输出结果 核心代码 输出结果 核心代码 #DL之NN:基于sklearn ...

  9. multiprocessing创建自定义进程类

    1.继承Process 2.编写自己的__init__,同时加载父类init方法 3.重写run方法,可以通过生成的对象调用start自动运行 from multiprocessing import ...

最新文章

  1. css的基本操作学习--css样式,选择器,hover,文字属性,文本属性,背景
  2. ios查看ipa是否函数特定字符_iOS 中基础字符判断函数收集(如判断大小写、数字等)...
  3. 【学习笔记】第四章——文件 I(文件管理、逻辑结构、目录与文件分配方式)
  4. sqlserver中某列转成以逗号连接的字符串及逆转、数据行转列列转行
  5. JSP基础(5)-JSP标准动作
  6. 北大的戴威,为何输给了三本的胡玮炜?
  7. loadstring的用法
  8. linux下安装matlab运行环境
  9. UE4 Gate效果
  10. excel怎么快速判断录入银行卡号是否正确?
  11. 【手机端测试的关注点】Android 和 IOS 两大主流系统测试点
  12. zhong yu gong si
  13. 7.9模拟比赛解题报告
  14. 蚂蚁金服服务注册中心 SOFARegistry 解析
  15. day03微信测试功能点思维导图
  16. Lambert(兰勃托)投影--我国天气图底图广泛采用的一种投影
  17. PullToRefresh+HorizontalScrollView+DrawerLayout
  18. 输入三个数判断能否构成直角三角形 C语言
  19. 美人松的高度1 c++信息学奥赛
  20. 内存卡只能读取不能写入,也不能格式化

热门文章

  1. css div随滚动 浮动,CSS div部分随的屏幕滚动而滚动的方法
  2. 有限元(FEM)基本知识速阅
  3. windows无法格式化的解决办法
  4. 教程-使用FirefoxSend搭建一个临时文件分享系统
  5. 蔚来汽车出售其电动方程式赛车车队 但仍提供赞助
  6. 成功自媒体人怎能不懂运营规划?
  7. 【论文阅读笔记】ISSTA 2021-Synthesize solving strategy for symbolic execution
  8. 【C++游戏设计】 通过函数设置字体的颜色
  9. 国家一级建造师—工程经济—第一章—第三节
  10. java 视频 合并成一个_Java 合并多个MP4视频文件