• heap


    heap

    push_heap

    对于第 i 个元素,其左子节点位于 2i 处,其右子节点位于 2i+1 处。

    根据元素排列方式,heap 可以分为:

    • 大顶堆:每个节点键值都大于或者等于其子节点的键值。
    • 小顶堆: 每个节点键值都小于或者等于其子节点的键值。
    //@ 堆中添加元素;关于push_heap操作的原型有两个
    //@ 注意: push_heap()操作之前必须保证新添加的元素已经加入到容器末尾
    //*		第一个版本使用operator<操作
    //*		template< class RandomIt >
    //*		void push_heap( RandomIt first, RandomIt last );
    //*********************************
    //*		第二个版本使用比较函数comp
    //*		template< class RandomIt, class Compare >
    //*		void push_heap( RandomIt first, RandomIt last,Compare comp );
    //*********************************
    //*	比较函数comp:comparison function which returns true if the first argument is less than the second. 
    //*	The signature of the comparison function should be equivalent to the following:
    //*		bool cmp(const Type1 &a, const Type2 &b);
    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

    将根节点取走后,先填入叶节点值,再将它拿来和其它两个子节点比较值,并与较大子节点对调位置,直到根节点的键值大于左右两个子节点,或者直到放至叶节点为止。

    //注意: 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);
    }
    

    make_heap

    //@ 创建堆
    //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));
    }
    

    sort_heap

    //@ 排序堆里面的内容
    //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 中,heap 并不是一种容器,而是一种算法,任何能够提供随机访问迭代器的容器都能支持 heap 的操作。
    • heap 不需要遍历内容,所以没有属于自己的迭代器。
  • 相关阅读:
    4-数组、指针与字符串1.3-this指针
    Linux命令----cp
    Linux命令----mv
    Linux命令----rm
    PHP7下的协程实现 转
    php生成器 yield 转
    python并发编程之多进程(实践篇) 转
    python 多进程
    线程创建 线程数
    多任务 执行
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/12608170.html
Copyright © 2020-2023  润新知