顺序容器(幕后英雄) — heap

heap不属于STL容器,它扮演者priority queue的助手。heap是一种完全二叉树,可由数组来实现,但heap需要动态改变大小,所以最终选择了vector作为底层容器。STL默认提供最大堆。

题外话:分析heap的源码就能清楚的理解堆这种数据结构的例程,而STL库代码的质量又很高,所以看堆的代码,STL源码是一个很好的选择。

为了满足完全二叉树的性质,新插入的元素一定最后一个叶子节点,也就是容器尾端,再然后再进行上滤操作,让新元素找到正确的位置。以push_heap为例:

template <class RandomAccessIterator> // 新元素已插入容器尾部

inline void push_heap(RandomAccessIterator first, RandomAccessIterator last) {

  __push_heap_aux(first, last, distance_type(first), value_type(first));

}

这个函数已经假设新插入元素已经位于vector的尾端,所以last指向新元素之后的一个位置。distance_type和value_type都是通过特性萃取机(iterator_traits)提取迭代器的相应类型:difference_type和value_type。提取过程如下:

template <class Iterator>

inline typename iterator_traits<Iterator>::difference_type*

distance_type(const Iterator&) {  // 决定迭代器difference_type

  return static_cast<typename iterator_traits<Iterator>::difference_type*>(0);

}

template <class Iterator>

inline typename iterator_traits<Iterator>::value_type*

value_type(const Iterator&) { // 决定迭代器value_type

  return static_cast<typename iterator_traits<Iterator>::value_type*>(0);

}

注意,这里使用了static_cast把0进行了转换,由于我们是需要迭代器所内嵌的类型,而不关心具体值,所以用0来代替是OK的。

push_heap内部调用函数__push_heap_aux,代码如下:

template <class RandomAccessIterator, class Distance, class T>

inline void __push_heap_aux(RandomAccessIterator first,

                            RandomAccessIterator last, Distance*, T*) {

  __push_heap(first, Distance((last - first) - 1), Distance(0), 

              T(*(last - 1)));  // 新插入元素值

}

最后两个参数只有类型名,没有参数名,印证了前面的说法。这个函数内部又调用了一个__push_heap函数,这个函数做了实际的上滤操作。在看__push_heap的源码之前,先分析一下它的四个参数:

  • first:迭代器,指向容器开头。
  • Distance((last - first) - 1):last - first - 1是新插入元素的下标值,这里用了一个C风格的类型转换,符合泛型思想。
  • Distance(0):根元素的下标值,同样进行了类型转换。
  • T(*(last - 1)):新插入元素的元素值,是上滤操比较操作的基础。

下面是核心代码:

template <class RandomAccessIterator, class Distance, class T>

void __push_heap(RandomAccessIterator first, Distance holeIndex,

                 Distance topIndex, T value) {

  Distance parent = (holeIndex - 1) / 2;  // 父节点下标

  while (holeIndex > topIndex && *(first + parent) < value) { // value为新插入元素值

    *(first + holeIndex) = *(first + parent);

    holeIndex = parent;             // 上移

    parent = (holeIndex - 1) / 2;   // 上移

  }    

  *(first + holeIndex) = value;

}

SGI STL的heap,元素是从vector的下标0开始排的,知道了这一点,看这段代码就很轻松了。

参考:

《STL源码剖析》 P172.

顺序容器(幕后英雄) — heap,码迷,mamicode.com

时间: 2024-10-11 17:21:31

顺序容器(幕后英雄) — heap的相关文章

顺序容器1(总体)

以下内容转自:https://www.cnblogs.com/QG-whz/p/5152963.html 阅读目录 0.前言 1.容器概论 2.std::array 2.1.底层数据结构 2.2.内存分配策略 2.3.array的优势在哪 3.forward_list 3.1.底层数据结构 3.2.forward_list特殊之一:forward_list不提供返回其大小的操作. 3.3.forward_list特殊之二:forward_list是唯一一个在给定位置之后插入新元素的容器. 3.4

第十篇:顺序容器vector,deque,list的选用规则

前言 常见的顺序容器主要有三种 - vector,deque,list.它们实现的功能相差不大,那么实际开发中该如何进行选择呢?本文将为你解答这个问题. 分析 由于这三种容器实现的数据结构原型不同(vector实现原型是顺序表,deque是双端队列,list是链表),因此这三种容器对插入删除以及访问操作的开销是不同的.为了编制出高效的程序,我们应当通过分析容器操作的开销来选择容器. 访问操作对容器选择的影响 1. vector容器的随机访问效率最高: 2. deque容器的随机访问效率也高: 3

c++顺序容器(1)

1.顺序容器 C++标准库中有三种顺序容器:vector list deque vector:支持快速随机访问,在尾部之外的位置插入或删除元素可能较慢 list:支持快速插入/删除,只支持双向顺序访问 deque:双端队列,支持快速随机访问,头尾插入和删除速度很快 还有array(不能添加和删除),forward_list,String(保存字符) 2.哪种顺序容器好? 通常,使用vector. (1)如果要求在容器的中间插入和删除元素,应使用list或forward_list. (2)如果只在

顺序容器

C++顺序容器 1.C++的顺序容器包括:vector.list.deque. 2.初始化顺序容器的5中方法: (1)Create an empty container: list<string> slist; vector<int> vec; (2)Create a container of some size. Each element is initialized to its default value.(Recall that the default value for

C++primer(第五版)第九章 顺序容器(容器的运用及其部分习题解答,C++11特性总结,重点章节内容较多)

顺序容器:为程序员提供了控制元素存储和访问顺序的能力.(无序容器)           1.顺序容器的概述           A.顺序容器的类型           vector:可变大小数组.支持快速随机访问.在尾部之外的位置插入或删除元素可能很慢.          deque:双端队列.支持快速随机访问.在头尾位置插入/删除速度很快.           list:双向链表.只支持双向顺序访问.在list中任何位置进行插入/删除操作速度都很快.          forword_list

顺序容器(二)--《C++ primer》

 前面已经简单介绍了顺序容器的定义以及一些操作,包括(添加,删除等),下面主要集中以代码的形式简单介绍一下相关用法,首先创建并初始化vector对象,一般有两大类: 1.分配指定数目元素,并初始化(分两种)          vector<int> ivec(10): vector<int> ivec(10,1): 2.把vecotr对象初始化为一段元素的副本 int a[10]={1,2,3,4,5,6,7,8,9,10}: vector<int> ivec(a,

c++顺序容器(2)

1.向顺序容器添加元素 c.push_back(t);c.emplace_back(args);//在c的尾部创建一个值为t或由args创建的元素,返回void.若在头部,back改为front c.insert(p,t);c,emplace(p,args);   c.insert(p,n,t);(插入n个)  c.insert(p,b,e);(迭代器范围) c.insert(p,i1);(列表) 注:a.除array和forward_list外,每个顺序容器都支持push_back. b.只有

C++ Primer 第九章顺序容器

一.综述 <vector>:可变大小数组.支持快速随机访问.在尾部之外的位置插入或删除元素可能很慢. <deque>:双端队列.支持快速随机访问.在头尾位置插入/删除速度很快. <list>:双向链表.只支持双向顺序访问.在list中任何位置进行插入/删除操作速度都很快. <forward_list>:单向链表.只支持单向顺序访问.在链表任何位置进行插入/删除操作速度都很快. <array>:固定大小数组.支持快速随机访问.不能添加或删除元素.

第九章:顺序容器

一.顺序容器概述:一个容器就是一些特定类型对象的集合 1.顺序容器类型:vector.deque.list.forward_list.array.string string和vector将元素保存在连续的内存空间,所以用下标访问很快,但是在中间位置添加或删除元素很耗时 list和forward_list在任何位置添加和删除操作都很快,但是访问一个元素只能遍历它,而且额外的内存开销很大 forward_list设计的目的是与最好的手写的单向链表数据结构相当的性能 deque支持下标访问,且在两端添