zoukankan      html  css  js  c++  java
  • 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--);
    }      

  • 相关阅读:
    做一个项目,平时都用到哪些工具提高效率(上)
    做项目时,如何做比较美观大方的数据输入窗体
    做一个项目,平时都用到哪些工具提高效率(中)
    类型的初试化器的调用时机
    数据加密小工具
    ASP.NET 开发知识小结
    做一个项目,平时都用到哪些工具提高效率(下)
    两道面试题目 关于new和override的
    js技巧,js找到html中的注释,js让客户端另存一段文本
    在适当的场合使用FlagsAttribute修饰枚举
  • 原文地址:https://www.cnblogs.com/xkfz007/p/2655620.html
Copyright © 2011-2022 走看看