• 【STL源码剖析读书笔记】【第4章】序列式容器之heap和priority_queue


    一、heap

    1、heap概述

    heap并不归属于STL容器组件,扮演priority queue的助手,binary max heap适合作为priority queue的底层机制。

    binary heap是一种completebinary tree,整棵binary tree除了最底层的叶子节点外是填满的,而最底层的叶子节点由左至右不得有空隙。

    利用array来存储completebinary tree的所有节点,将array#0元素保留,那么当complete binary tree的某个节点位于arrayi处时,其左子节点必位于array2i处,右子节点必位于array2i+1处,父节点必位于i/2处。

    heap分为max-heapmin-heap两种,前者每个节点的键值都大于或等于其子节点的值,后者每个节点的键值都小于或等于其子节点的值。max-heap中最大值在根节点,min-heap最小值在根节点。底层存储结构为vector或者array

    2、push_heap算法


    3、pop_heap算法

    4、sort_heap算法


    5、make_heap算法

    将一段现有的数据转化为一个heap

    6、heap源码

    //在STL中,heap不作为容器,只是提供了关于Heap操作的算法。
    //heap没有自己的迭代器,只要支持RandomAccessIterator的容器都可以作为Heap容器
    #ifndef __SGI_STL_INTERNAL_HEAP_H
    #define __SGI_STL_INTERNAL_HEAP_H
    
    __STL_BEGIN_NAMESPACE
    
    #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
    #pragma set woff 1209
    #endif
    
    // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_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()操作, 执行完操作后要自己将容器尾元素弹出
    //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);
    }
    
    #if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
    #pragma reset woff 1209
    #endif
    
    __STL_END_NAMESPACE
    
    #endif /* __SGI_STL_INTERNAL_HEAP_H */
    
    // Local Variables:
    // mode:C++
    // End:

    7、heap测试实例

    #include<vector>
    #include<iostream>
    #include<algorithm> //heap algorithm
    using namespace std;
    
    int main(void){
    	{   //test heap(底层以vector完成)
    		int ia[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };
    		vector<int> ivec(ia, ia + 9);
    
    		make_heap(ivec.begin(), ivec.end());
    		for (int i = 0; i < ivec.size(); ++i)
    			cout << ivec[i] << ' ';
    		cout << endl;
    
    		ivec.push_back(7);
    		push_heap(ivec.begin(), ivec.end());
    		for (int i = 0; i < ivec.size(); ++i)
    			cout << ivec[i] << ' ';
    		cout << endl;
    
    		pop_heap(ivec.begin(), ivec.end());
    		cout << ivec.back() << endl;
    		ivec.pop_back();
    
    		for (int i = 0; i < ivec.size(); ++i)
    			cout << ivec[i] << ' ';
    		cout << endl;
    
    		sort_heap(ivec.begin(), ivec.end());
    		for (int i = 0; i < ivec.size(); ++i)
    			cout << ivec[i] << ' ';
    		cout << endl;
    	}
    	{   //test heap (底层以array 完成)
    		int ia[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };
    		make_heap(ia, ia + 9);
    
    
    		sort_heap(ia, ia + 9);
    		for (int i = 0; i < 9; ++i)
    		{
    			cout << ia[i] << ' ';
    		}
    		cout << endl;
        }
    	{   //test heap (底层以array完成)
    		int ia[6] = { 4, 1, 7, 6, 2, 5 };
    		make_heap(ia, ia + 6);
    		for (int i = 0; i < 6; ++i)
    			cout << ia[i] << ' ';
    		cout << endl;
    	}
    	system("pause");
    	return 0;
    }
    

    二、priority_queue

    1、priority_queue概述

    priority_queue是一个拥有权值观念的queue,它允许加入新元素、移除旧元素、审视元素值等功能。只允许在底端加入元素,并从顶端取出元素,除此之外别无其它存取元素的途径。

    priority_queue缺省情况下是以vector为底层容器,再加上heap处理规则,STLpriority_queue往往不被归类为container(容器),而被归类为containeradapter。

    2、测试实例

    #include<queue>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int main(void){
    	//test priority queue...
    	int ia[9] = { 0, 1, 2, 3, 4, 8, 9, 3, 5 };
    	priority_queue<int> ipq(ia, ia + 9);
    	cout << "size= " << ipq.size() << endl;
    
    	for (int i = 0; i < ipq.size(); ++i)
    		cout << ipq.top() << ' ';
    	cout << endl;
    
    	while (!ipq.empty()){
    		cout << ipq.top() << ' ';
    		ipq.pop();
    	}
    	cout << endl;
    
    	system("pause");
    	return 0;
    }
    


  • 相关阅读:
    mysql同步 小问题
    通过 XtraBackup 实现不停机不锁表搭建主从同步
    grep -A -B选项详解和mysqlbinlog
    MySQL存储过程中的3种循环
    mysql利用存储过程批量插入数据
    React routerV4 笔记
    数据结构算法基础定义
    网站性能优化
    去重除了indexOf的其他方法(使用对象Key的方法)及统计重复次数
    立即执行函数的两种写法及闭包
  • 原文地址:https://www.cnblogs.com/ruan875417/p/4558316.html
Copyright © 2020-2023  润新知