STL中的堆(heap)操作

STL中并没有把heap作为一种容器组件,heap的实现亦需要更低一层的容器组件(诸如list,array,vector)作为其底层机制。Heap是一个类属算法,包含在algorithm头文件中。
  在STL中为堆heap的创建和操作提供了4种算法:make_heap,pop_heap,push_heap和sort_heap。
1. push_heap: 假定区间[first,last-1)已经包含了一个堆,把区间[first,last)调整为一个堆(从而     把last-1位置上的元素压入堆。
    函数原型:
void push_heap(first,last);
void push_heap(first,last,compare_fuction).
push_heap是将[first,last)调整为堆。它假定[first,last-1)是一个堆。如果[first,last-1)不是一个堆,push_heap是不负责将它调整为堆的。其实push_heap的操作就是对插入容器的最后一个元素进行调整:判断它与父节点大小,如果大于父节点就将父节点下移到该位置,然后继续将它与之后的父节点比较,知道比较到根节点。所以,如果原来[first,last-1)不是一个堆的话,push_heap后的结果不保证是一个堆。
SGI STL在实现push_heap的时候采用了其他的一些辅助函数,包括__push_heap和__push_heap_aux。
(1)__push_heap函数的源代码如下:
template <class _RandomAccessIterator, class _Distance, class _Tp>       
void __push_heap(_RandomAccessIterator __first, _Distance __holeIndex, _Distance __topIndex, _Tp __value)
{
  _Distance __parent = (__holeIndex - 1) / 2;
  while (__holeIndex > __topIndex && *(__first + __parent) < __value) {
    *(__first + __holeIndex) = *(__first + __parent);
    __holeIndex = __parent;
    __parent = (__holeIndex - 1) / 2;
  }    
  *(__first + __holeIndex) = __value;
}
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;
}

该函数主要的功能就是将索引为__holeIndex、值为value的元素,依照堆的大小关系,上调到topIndex元素位置下面(甚至会调整到__topIndex元素处)。参数__first给出区间首元素的起始位置,以便其他的元素可用数组方式的索引值访问出来。
(2)__push_heap_aux函数的源代码如下:
template <class _RandomAccessIterator, class _Distance, class _Tp>
 inline void  __push_heap_aux(_RandomAccessIterator __first, _RandomAccessIterator __last, _Distance*, _Tp*)
 {
   __push_heap(__first, _Distance((__last - __first) - 1), _Distance(0), _Tp(*(__last - 1)));
 }
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);
}

该函数设定__topIndex=0(即根节点为上调界限元素),将迭代器区间[__first,__last)的最后一个元素*(__last-1)调整到正确位置,其他的元素依次下调. 其中__last-__first-1就是*(__last-1)元素的索引值.
(3) push_heap的源代码如下:
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 _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));
}

可以看到push_heap函数只是简单的调用__push_heap_aux函数.

2. make_heap:利用区间[first,last)中的元素构造一个heap。
  函数原型:
void make_heap(first,last)
void make_heap(first,last ,compare_fuction)
SGI C++ STL的make_heap算法函数是由stl_heap.h文件提供。
它利用了辅助函数__adjust_heap,__push_heap和__make_heap.
(1) __adjust_heap的源代码如下(省略带有比较函数的):
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);
}

该函数其实就是参数__first迭代器指示整个二叉树的起始处, __len参数为二叉树的元素个数, __holeIndex和__value表示需要调整的节点的索引和它的值.
(2) 辅助__make_heap函数源代码如下:
template <class _RandomAccessIterator, class _Tp, class _Distance>
void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Tp*, _Distance*)
{
  if (__last - __first < 2return;
  _Distance __len = __last - __first;
  _Distance __parent = (__len - 2)/2;
    
  while (true) {
    __adjust_heap(__first, __parent, __len, _Tp(*(__first + __parent)));
    if (__parent == 0return;
    __parent--;
  }
}

该函数利用每层局部调整的__adjust_heap函数再实现__make_heap函数来完成对整个二叉树进行堆调整.
(3) make_heap的源代码:
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));
}
直接调用__make_heap来实现的.

3. pop_heap:  假定区间[first,last)中已包含一个堆,将first位置和last-1位置上的值交换,重新把[first,last-1)调整为一个堆。
    函数原型:
void pop_heap(first,last);
void pop_heap(first,last,compare_fuction)
pop_heap主要使用了__pop_heap和__pop_heap_aux两个辅助函数.
(1) __pop_heap的源代码:
template <class _RandomAccessIterator, class _Tp, class _Distance>
 inline void  __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
            _RandomAccessIterator __result, _Tp __value, _Distance*)
 {
   *__result = *__first;
   __adjust_heap(__first, _Distance(0), _Distance(__last - __first), __value);
 }  

__pop_heap辅助函数将堆中的根节点与*result元素交换,再对以*result为根节点的元素的二叉树重新调整为堆.
(2) __pop_heap_aux代码:
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));
}

(3) pop_heap的源代码:
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));
}   
  
直接调用__pop_heap_aux完成  
    
4. sort_heap: 对存储在堆中的元素进行排序。
    函数原型:
void sort_heap(first,last);
void sort_heap(first,last,compare_fuction)
时间复杂度是O(nlogn)
实现代码很简单就是不断的调用pop_heap函数将最大元素移到最后.
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--);
}      

posted @ 2012-08-25 08:06  Mr.Rico  阅读(853)  评论(0编辑  收藏  举报