STL之堆和优先队列

STL中的heap是用数组来进行模拟的,heap 本身的定义就是一颗完全的二叉树(注意和满二叉树的区别)。

heap分为大根堆和小根堆。

堆的主要操作由构建堆,调整堆,这两个。

其中有一个heap算法就是在此基础之上的。

构建好一颗大根堆,然后 将根顶元素和最后一个元素呼唤,将堆的大小减1,同时再次调整堆为大根堆,重复直至堆的大小为0。

由于堆结构本上是类似分组划分的,其中修改也就是修改这条路径上的,和其他元素没有关系,因此,每次修改的时候也就是路径长度,也就是二叉树的高度。

template <class _RandomAccessIterator, class _Distance, class _Tp>
void
__push_heap(_RandomAccessIterator __first,
            _Distance __holeIndex, _Distance __topIndex, _Tp __value)
{//当前节点标号为__holeIndex- 1即为新插入元素标号,因为根节点标号是从0开始,所以这里要-1
  _Distance __parent = (__holeIndex - 1) / 2;//找出当前节点的父节点
  //尚未达到根节点,且所插入数据value大于父节点的关键字值
  while (__holeIndex > __topIndex && *(__first + __parent) < __value) {
    *(__first + __holeIndex) = *(__first + __parent);//交换当前节点元素与其父节点元素的值
    __holeIndex = __parent;//更新当前节点标号,上溯
    __parent = (__holeIndex - 1) / 2;//更新父节点
  }   //持续达到根节点,或满足heap的性质
  *(__first + __holeIndex) = __value;//插入正确的位置
}

template <class _RandomAccessIterator, class _Distance, class _Tp>
inline void
__push_heap_aux(_RandomAccessIterator __first,
                _RandomAccessIterator __last, _Distance*, _Tp*)
{
    //__last - __first) - 1表示插入后元素的个数,也是容器的最后一个下标数字
    //新插入的元素必须位于容器的末尾
    __push_heap(__first, _Distance((__last - __first) - 1), _Distance(0),
              _Tp(*(__last - 1)));
}

//第一个版本push_heap默认是operator<操作
template <class _RandomAccessIterator>
inline void
push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
  __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
                 _LessThanComparable);
  __push_heap_aux(__first, __last,
                  __DISTANCE_TYPE(__first), __VALUE_TYPE(__first));
}

template <class _RandomAccessIterator, class _Distance, class _Tp,
          class _Compare>
void
__push_heap(_RandomAccessIterator __first, _Distance __holeIndex,
            _Distance __topIndex, _Tp __value, _Compare __comp)
{
  _Distance __parent = (__holeIndex - 1) / 2;
  while (__holeIndex > __topIndex && __comp(*(__first + __parent), __value)) {
    *(__first + __holeIndex) = *(__first + __parent);
    __holeIndex = __parent;
    __parent = (__holeIndex - 1) / 2;
  }
  *(__first + __holeIndex) = __value;
}

template <class _RandomAccessIterator, class _Compare,
          class _Distance, class _Tp>
inline void
__push_heap_aux(_RandomAccessIterator __first,
                _RandomAccessIterator __last, _Compare __comp,
                _Distance*, _Tp*)
{
  __push_heap(__first, _Distance((__last - __first) - 1), _Distance(0),
              _Tp(*(__last - 1)), __comp);
}
//第二个版本push_heap自定义比较操作函数comp
template <class _RandomAccessIterator, class _Compare>
inline void
push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
          _Compare __comp)
{
  __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
  __push_heap_aux(__first, __last, __comp,
                  __DISTANCE_TYPE(__first), __VALUE_TYPE(__first));
}

//注意: pop_heap()操作, 执行完操作后要自己将容器尾元素弹出
//default (1):
//            template <class RandomAccessIterator>
//            void pop_heap (RandomAccessIterator first, RandomAccessIterator last);
//custom (2):
//            template <class RandomAccessIterator, class Compare>
//            void pop_heap (RandomAccessIterator first, RandomAccessIterator last,
//                 Compare comp);
//***********************************************************************
template <class _RandomAccessIterator, class _Distance, class _Tp>
void
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
              _Distance __len, _Tp __value)
{
  _Distance __topIndex = __holeIndex;//根节点标号
  _Distance __secondChild = 2 * __holeIndex + 2;//获取子节点
  while (__secondChild < __len) {//若子节点标号比总的标号数小
    if (*(__first + __secondChild) < *(__first + (__secondChild - 1)))
      __secondChild--;//找出堆中最大关键字值的节点
    //若堆中存在比新根节点元素(即原始堆最后节点关键字值)大的节点,则交换位置
    *(__first + __holeIndex) = *(__first + __secondChild);
    __holeIndex = __secondChild;//更新父节点
    __secondChild = 2 * (__secondChild + 1);//更新子节点
  }
  if (__secondChild == __len) {
    *(__first + __holeIndex) = *(__first + (__secondChild - 1));
    __holeIndex = __secondChild - 1;
  }
  __push_heap(__first, __holeIndex, __topIndex, __value);
}

template <class _RandomAccessIterator, class _Tp, class _Distance>
inline void
__pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
           _RandomAccessIterator __result, _Tp __value, _Distance*)
{
  *__result = *__first;//把原始堆的根节点元素放在容器的末尾
  //调整剩下的节点元素,使其成为新的heap
  __adjust_heap(__first, _Distance(0), _Distance(__last - __first), __value);
}

template <class _RandomAccessIterator, class _Tp>
inline void
__pop_heap_aux(_RandomAccessIterator __first, _RandomAccessIterator __last,
               _Tp*)
{
  __pop_heap(__first, __last - 1, __last - 1,
             _Tp(*(__last - 1)), __DISTANCE_TYPE(__first));
}

template <class _RandomAccessIterator>
inline void pop_heap(_RandomAccessIterator __first,
                     _RandomAccessIterator __last)
{
  __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
                 _LessThanComparable);
  __pop_heap_aux(__first, __last, __VALUE_TYPE(__first));
}

template <class _RandomAccessIterator, class _Distance,
          class _Tp, class _Compare>
void
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
              _Distance __len, _Tp __value, _Compare __comp)
{
  _Distance __topIndex = __holeIndex;
  _Distance __secondChild = 2 * __holeIndex + 2;
  while (__secondChild < __len) {
    if (__comp(*(__first + __secondChild), *(__first + (__secondChild - 1))))
      __secondChild--;
    *(__first + __holeIndex) = *(__first + __secondChild);
    __holeIndex = __secondChild;
    __secondChild = 2 * (__secondChild + 1);
  }
  if (__secondChild == __len) {
    *(__first + __holeIndex) = *(__first + (__secondChild - 1));
    __holeIndex = __secondChild - 1;
  }
  __push_heap(__first, __holeIndex, __topIndex, __value, __comp);
}

template <class _RandomAccessIterator, class _Tp, class _Compare,
          class _Distance>
inline void
__pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
           _RandomAccessIterator __result, _Tp __value, _Compare __comp,
           _Distance*)
{
  *__result = *__first;
  __adjust_heap(__first, _Distance(0), _Distance(__last - __first),
                __value, __comp);
}

template <class _RandomAccessIterator, class _Tp, class _Compare>
inline void
__pop_heap_aux(_RandomAccessIterator __first,
               _RandomAccessIterator __last, _Tp*, _Compare __comp)
{
  __pop_heap(__first, __last - 1, __last - 1, _Tp(*(__last - 1)), __comp,
             __DISTANCE_TYPE(__first));
}

template <class _RandomAccessIterator, class _Compare>
inline void
pop_heap(_RandomAccessIterator __first,
         _RandomAccessIterator __last, _Compare __comp)
{
  __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
  __pop_heap_aux(__first, __last, __VALUE_TYPE(__first), __comp);
}

//创建堆
//default(1):
//            template <class RandomAccessIterator>
//            void make_heap (RandomAccessIterator first, RandomAccessIterator last);
//custom (2):
//            template <class RandomAccessIterator, class Compare>
//            void make_heap (RandomAccessIterator first, RandomAccessIterator last,Compare comp );
  //********************************************************************************
template <class _RandomAccessIterator, class _Tp, class _Distance>
void
__make_heap(_RandomAccessIterator __first,
            _RandomAccessIterator __last, _Tp*, _Distance*)
{
  if (__last - __first < 2) return;
  _Distance __len = __last - __first;
  _Distance __parent = (__len - 2)/2;

  while (true) {
    __adjust_heap(__first, __parent, __len, _Tp(*(__first + __parent)));
    if (__parent == 0) return;
    __parent--;
  }
}

template <class _RandomAccessIterator>
inline void
make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
  __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
                 _LessThanComparable);
  __make_heap(__first, __last,
              __VALUE_TYPE(__first), __DISTANCE_TYPE(__first));
}

template <class _RandomAccessIterator, class _Compare,
          class _Tp, class _Distance>
void
__make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
            _Compare __comp, _Tp*, _Distance*)
{
  if (__last - __first < 2) return;
  _Distance __len = __last - __first;
  _Distance __parent = (__len - 2)/2;

  while (true) {
    __adjust_heap(__first, __parent, __len, _Tp(*(__first + __parent)),
                  __comp);
    if (__parent == 0) return;
    __parent--;
  }
}

template <class _RandomAccessIterator, class _Compare>
inline void
make_heap(_RandomAccessIterator __first,
          _RandomAccessIterator __last, _Compare __comp)
{
  __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
  __make_heap(__first, __last, __comp,
              __VALUE_TYPE(__first), __DISTANCE_TYPE(__first));
}

//排序堆里面的内容
//default(1):
//            template <class RandomAccessIterator>
//            void sort_heap (RandomAccessIterator first, RandomAccessIterator last);
//custom (2):
//            template <class RandomAccessIterator, class Compare>
//            void sort_heap (RandomAccessIterator first, RandomAccessIterator last,
//                          Compare comp);
//**************************************************************************
template <class _RandomAccessIterator>
void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
  __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
                 _LessThanComparable);
  while (__last - __first > 1)
    pop_heap(__first, __last--);//每次取出根节点元素,直到heap为空
}

template <class _RandomAccessIterator, class _Compare>
void
sort_heap(_RandomAccessIterator __first,
          _RandomAccessIterator __last, _Compare __comp)
{
  __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
  while (__last - __first > 1)
    pop_heap(__first, __last--, __comp);
}

不过 STL提供了完整的封装操作,可以直接用make_heap来构建堆。 sort_heap来对堆进行排序。 很是方便的。

STL中的优先队列是利用一个大根堆,用vector来模拟完全二叉树的结构。 优先队列包含在queue这个头文件下面。

原文地址:https://www.cnblogs.com/randyniu/p/9249549.html

时间: 2024-11-04 19:13:24

STL之堆和优先队列的相关文章

堆与优先队列

当我们需要高效的完成以下操作时: 1.插入一个元素 2.取得最小(最大)的数值,并且删除 能够完成这种操作的数据结构叫做优先队列 而能够使用二叉树,完成这种操作的数据结构叫做堆(二叉堆) 堆与优先队列的时间复杂度: 若共有n个元素,则可在O(logn)的时间内完成上述两种操作 堆的结构如下图: 堆最重要的性质就是儿子的值一定不小于父亲的值,且堆从上到下,从左到右紧密排列. 堆的操作: 当我们希望向堆中插入元素时,堆的内部会进行如下操作(以插入元素3为例): (1.在堆的末尾插入该值) (2.不断

堆和优先队列

1 二叉堆和优先队列的概念 1.1 二叉堆 二叉堆堆是一个数组,它可以被看成一个近似的完全二叉树,树上每一个结点对应数组中的一个元素.除了最底层外,该树是完全充满的,而且是从左到右填充.表示堆的数组A包括两个属性:A.length给出数组元素的个数,A.heap_size表示有多少个堆元素存储在该数组中,这里,0<=A.heap_size<=A.length. 如下图所示: 堆可以分成两种:最大堆和最小堆.在最大堆中,任何节点的值都大于等于其孩子的值,故根节点是数组中的最大数所在节点.反之,最

[ACM] POJ 1442 Black Box (堆,优先队列)

Black Box Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7099   Accepted: 2888 Description Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black Box is empt

数据结构-堆实现优先队列(java)

队列的特点是先进先出.通常都把队列比喻成排队买东西,大家都很守秩序,先排队的人就先买东西.但是优先队列有所不同,它不遵循先进先出的规则,而是根据队列中元素的优先权,优先权最大的先被取出.这就很像堆的特征:总是移除优先级最高的根节点. 重点:优先级队列,是要看优先级的,谁的优先级更高,谁就先得到权限.不分排队的顺序! 上篇文章解释了堆的概念实现,现在用堆实现优先队列: //最大堆 import java.util.ArrayList; public class Heap<E extends Com

堆以及优先队列

#include<iostream> using namespace std; int A[]={0,4,1,3,2,16,9,10,14,8,7}; int left(int i){ return 2*i; } int right(int i){ return 2*i+1; } int parent(int i){ return i/2; } void heap(int i){ int l=left(i); int r=right(i); int larget; if(l<=10&am

c++ STL:队列queue、优先队列priority queue 的使用

说明:本文全文转载而来,原文链接:http://www.cppblog.com/wanghaiguang/archive/2012/06/05/177644.html C++ Queues(队列) C++队列是一种容器适配器,它给予程序员一种先进先出(FIFO)的数据结构.1.back() 返回一个引用,指向最后一个元素2.empty() 如果队列空则返回真3.front() 返回第一个元素4.pop() 删除第一个元素5.push() 在末尾加入一个元素6.size() 返回队列中元素的个数

最小堆(优先队列)基本概念,即一个完整建立,插入,删除代码

堆(优先队列)priority queue特殊的队列,取出元素的顺序是依照元素的优先权(关键字)大小,而出元素进入队列的先后顺序操作:查找最大值(最小值),删除(最大值) 数组:链表:有序数组:有序链表: 采用二叉搜索树? NO 采用完全二叉树 YES堆的连个特性结构性:用数组表示的完全二叉树:有序性:任一结点的关键字是其字树所有结点的最大值(或最小值) 最大堆(MaxHeap)也称大顶堆:最大值 最小堆(MinHeap)也称"小顶堆":最小值 从根节点到任意结点路径上结点序列的有序性

【转】用大顶堆实现优先队列

队列的特点是先进先出.通常都把队列比喻成排队买东西,大家都很守秩序,先排队的人就先买东西.但是优先队列有所不同,它不遵循先进先出的规则,而是根据队列中元素的优先权,优先权最大的先被取出.这就很像堆的特征:总是移除优先级最高的根节点. 重点:优先级队列,是要看优先级的,谁的优先级更高,谁就先得到权限.不分排队的顺序! 用堆实现优先队列: //最大堆 import java.util.ArrayList; public class Heap<E extends Comparable>{ priva

0038数据结构之堆和优先队列

优先队列:出队顺序和入队顺序无关,而是和优先级有关(优先级高的先出队) 如果使用普通线性结构或者顺序线性结构实现优先队列,出队或者入队总有一方是O(n)级别的:如果使用堆实现优先队列,能使入队和出队的时间复杂度都是O(logn),效率是极高的. 二叉堆是一颗完全二叉树,不一定是满二叉树,但是确实节点的那部分一定是在整棵树的右下侧.满足的规律:1)根节点最大, 2)确实节点的那部分在整棵树的右下侧.(低层次的节点不一定大于高层次的节点) 下图是一颗最大堆: 可以用数组存储: 从数组1位置开始存储: