前面两篇介绍了gcc4.8的vector和list的源码实现,这是stl最常用了两种序列式容器。除了容器之外,stl还提供了一种借助容器实现特殊操作的组件,谓之适配器,比如stack,queue,priority queue等,本文就介绍gcc4.8的priority queue的源码实现。

顾名思义,priority queue是带有优先级的队列,所以元素必须提供<操作符,与vector和list不同,priority queue允许加入元素,但是取出时只能取出优先级最高的元素。

一、 priority queue定义

priority queue没有基类

template<typename _Tp, typename _Sequence = vector<_Tp>,
typename _Compare = less<typename _Sequence::value_type> >
class priority_queue
{
public:
typedef typename _Sequence::value_type value_type;
typedef typename _Sequence::reference reference;
typedef typename _Sequence::const_reference const_reference;
typedef typename _Sequence::size_type size_type;
typedef _Sequence container_type; protected:
_Sequence c;
_Compare comp;
…...

priority queue底层默认使用vector,含有两个成员,vector c存储数据,comp是一个仿函数,用来比较数据大小。

二、 priority queue构造方式

可以用vector直接初始化priority queue,也可以任意迭代器或者数组指针初始化。

explicit
priority_queue(const _Compare& __x,
const _Sequence& __s)
: c(__s), comp(__x)
{ std::make_heap(c.begin(), c.end(), comp); } explicit
priority_queue(const _Compare& __x = _Compare(),
_Sequence&& __s = _Sequence())
: c(std::move(__s)), comp(__x)
{ std::make_heap(c.begin(), c.end(), comp); }
template<typename _InputIterator>
priority_queue(_InputIterator __first, _InputIterator __last,
const _Compare& __x,
const _Sequence& __s)
: c(__s), comp(__x)
{
__glibcxx_requires_valid_range(__first, __last);
c.insert(c.end(), __first, __last);
std::make_heap(c.begin(), c.end(), comp);
}
template<typename _InputIterator>
priority_queue(_InputIterator __first, _InputIterator __last,
const _Compare& __x = _Compare(),
_Sequence&& __s = _Sequence())
: c(std::move(__s)), comp(__x)
{
__glibcxx_requires_valid_range(__first, __last);
c.insert(c.end(), __first, __last);
std::make_heap(c.begin(), c.end(), comp);
}

将元素全部插入priority queue后,使用 make_heap将其建成最大堆,

template<typename _RandomAccessIterator>
void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{ typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type
_DistanceType;
if (__last - __first < )
return;
const _DistanceType __len = __last - __first;
_DistanceType __parent = (__len - ) / ;
while (true)
{
_ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value));
if (__parent == )
return;
__parent--;
}
}

__adjust_heap是一个下溯过程,从最后一个非叶子节点往前一个个执行下溯过程,使得以其为根节点的子树是一个最大堆。

template<typename _RandomAccessIterator, typename _Distance,
typename _Tp, typename _Compare>
void __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
_Distance __len, _Tp __value, _Compare __comp)
{
const _Distance __topIndex = __holeIndex;
_Distance __secondChild = __holeIndex;
while (__secondChild < (__len - ) / )
{
__secondChild = * (__secondChild + );
if (__comp(*(__first + __secondChild),
*(__first + (__secondChild - ))))
__secondChild--;
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
__holeIndex = __secondChild;
}
if ((__len & ) == && __secondChild == (__len - ) / )
{
__secondChild = * (__secondChild + );
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first
+ (__secondChild - )));
__holeIndex = __secondChild - ;
}
std::__push_heap(__first, __holeIndex, __topIndex,
_GLIBCXX_MOVE(__value), __comp);
}

三、 priority queue的元素操作

priority queue只有push和pop两个主要操作,push增加新的元素,

void push(const value_type& __x)
{
c.push_back(__x);
std::push_heap(c.begin(), c.end(), comp);
}

先放到最后一个位置,再使用 push_heap执行一个上溯操作,将插入元素移动到合适位置,保证整个queue仍然是个最大堆。

template<typename _RandomAccessIterator, typename _Distance, typename _Tp>
void
__push_heap(_RandomAccessIterator __first,
_Distance __holeIndex, _Distance __topIndex, _Tp __value)
{
_Distance __parent = (__holeIndex - ) / ;
while (__holeIndex > __topIndex && *(__first + __parent) < __value)
{
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent));
__holeIndex = __parent;
__parent = (__holeIndex - ) / ;
}
*(__first + __holeIndex) = _GLIBCXX_MOVE(__value);
}

pop操作移除堆顶元素,

void pop()

{

std::pop_heap(c.begin(), c.end(), comp);

c.pop_back();

}

由于使用的是vector,如果移除第一个元素再make_heap的话代价会很大。这里先将第一个元素和最后一个元素交换,删除最后一个元素,再从第一个元素做一次下溯过程,就建成了新的最大堆。

stl源码分析之priority queue的更多相关文章

  1. STL源码分析《4》----Traits技术

    在 STL 源码中,到处可见 Traits 的身影,其实 Traits 不是一种语法,更确切地说是一种技术. STL库中,有一个函数叫做 advance, 用来将某个迭代器(具有指针行为的一种 cla ...

  2. STL源码分析《3》----辅助空间不足时,如何进行归并排序

    两个连在一起的序列 [first, middle) 和 [middle, last) 都已经排序, 归并排序最核心的算法就是 将 [first, middle) 和 [middle, last) 在  ...

  3. STL 源码分析《1》---- list 归并排序的 迭代版本, 神奇的 STL list sort

    最近在看 侯捷的 STL源码分析,发现了以下的这个list 排序算法,乍眼看去,实在难以看出它是归并排序. 平常大家写归并排序,通常写的是 递归版本..为了效率的考虑,STL库 给出了如下的 归并排序 ...

  4. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  5. STL 源码分析《2》----nth_element() 使用与源码分析

    Select 问题: 在一个无序的数组中 找到第 n 大的元素. 思路 1: 排序,O(NlgN) 思路 2: 利用快排的 RandomizedPartition(), 平均复杂度是 O(N) 思路 ...

  6. stl源码分析之allocator

    allocator封装了stl标准程序库的内存管理系统,标准库的string,容器,算法和部分iostream都是通过allocator分配和释放内存的.标准库的组件有一个参数指定使用的allocat ...

  7. STL源码分析与实现-stl_list容器

    1. stl_list 介绍 今天我们来总结一下stl_List, 通过之前介绍单链表的文章,其实对链表的基本操作已经十分熟悉了,那对于stl_list,无非就是链表结构不一样,至于其中的增删改查的细 ...

  8. STL 源码分析六大组件-allocator

    1. allocator 基本介绍 分配器(allocator))是C ++标准库的一个组件, 主要用来处理所有给定容器(vector,list,map等)内存的分配和释放.C ++标准库提供了默认使 ...

  9. STL源码分析之迭代器

    前言 迭代器是将算法和容器两个独立的泛型进行调和的一个接口. 使我们不需要关系中间的转化是怎么样的就都能直接使用迭代器进行数据访问. 而迭代器最重要的就是对operator *和operator-&g ...

随机推荐

  1. ASP.Net MVC的学习

    套种间作,也挺有意思的——近来学习感悟.DRP学习的同时,折腾了点以前不曾学习但是却很多次耳闻过的东西——Asp.Net中的MVC架构模式. 一.是什么? MVC,即(Model-View-Contr ...

  2. Linux 启动进程结束进程通用代码

    linux启动springboot项目 start.sh #!/bin/sh rm -f tpid nohup java -jar restDate--SNAPSHOT.jar --spring.pr ...

  3. 面试官问你JS基本类型时他想知道什么?

    面试的时候我们经常会被问答js的数据类型.大部分情况我们会这样回答包括:1.基本类型(值类型或者原始类型): Number.Boolean.String.NULL.Undefined以及ES6的Sym ...

  4. ionic3 监听软键盘的高度

    ionic1 和普通cordova的大家都知道 就是看ionic3 和4 https://blog.csdn.net/sean_css/article/details/70243893 ionic c ...

  5. CentOS6安装各种大数据软件 第七章:Flume安装与配置

    相关文章链接 CentOS6安装各种大数据软件 第一章:各个软件版本介绍 CentOS6安装各种大数据软件 第二章:Linux各个软件启动命令 CentOS6安装各种大数据软件 第三章:Linux基础 ...

  6. easyui图标

    只要在icons属性上,加上图标对应的名字,easyUI就会显示对应的图标,这些图标都是easyui内置的.

  7. 解决 Cydia 源显示空白的问题

    打开 Cydia 所有源都显示空白,没有任何插件,已安装的列表也显示空白,解决方法是下载 var.lib_tar 包 下载链接: https://pan.baidu.com/s/1jzJ8KehoBo ...

  8. grep基础用法详解

    适合初学linux的人学得比较凌乱的人看这个也能理理思路学得更系统,节约你的学习时间,提高效率,但是思维导图的作用是帮人理清思路不会迷失在细节中,细节补充学习请参考https://www.cnblog ...

  9. 读书笔记《PHP高级程序设计、模式、框架与测试》

    序言 闲来无事,下载了一些电子书,然后看书名不错<PHP高级程序设计_模式.框架与测试>,翻了一下虽然书有点老了但是讲的内容经常会碰到!给大家推荐一下,然后这里放上我的读书笔记,每日更新. ...

  10. NCBI SRA数据库使用详解

    转:https://shengxin.ren/article/16 https://www.cnblogs.com/lmt921108/p/7442699.html 批量下载SRA http://ww ...