• 深入理解heap


    binary heap

    binary heap是一种complete binary tree(完全二叉树),也就是说,整棵binary tree除了最底层的叶节点之外,是填满的,而最底层的叶节点由左到右又不得有空隙,如图所示:

    在这里插入图片描述
    complete binary tree整棵树内没有任何节点漏洞,这带来一个极大的好处:我们可以利用array来存储所有节点,假设动用一个小技巧,将array的#0元素保留,那么当complete binary tree中的某个节点位于array的i处时,其左节点必位于array的2i处,其右节点必位于array的2i+1处,其父节点必位于i/2处(此处的"/‘’权且代表高斯符号,取其整数),这种通过array表述tree的方式,我们称为隐式表述法
    array的缺点是无法动态改变大小,以vector代替array是更好的选择
    根据元素排列方式,heap可分为max—heap和min—heap两种,前者每个节点的键值都大于或等于其子节点键值,后者的每个节点键值都小于或等于其子节点键值

    heap算法

    push_heap算法

    下图所示的是push_heap算法的实际操演情况,为了满足complete binary tree的条件,新加入的元素一定要放在最下一层作为叶节点,并填补在由左至右的第一个空格,也就是把新元素插入在底层vector的end()处
    在这里插入图片描述
    新元素是否适用于其现有位置?为满足max-heap的条件,我们执行一个所谓的percolate up(上溯)程序,将新节点拿来与其父节点比较,如果其键值比父节点大,就父子对换位置,如此一直上溯,直到不需对换或直到根结点为止
    下面是算法的实现细节:

    template<class RandomAccessIterator,class Distance,class T>
    void _push_heap(RandomAccessIterator first,Distance holeIndex,Distance topIndex,T value)
    {
    	Distance parent=(holdIndex-1)/2;//找出父节点
    	while(holeIndex>topIndex&&*(first+parent)<value)
    	{
    		//当尚未到达顶端,且父节点小于新值
    		//由于以上使用operator<.可知STL heap是一种max-heap
    		*(first+holeIndex)=*(first+parent);//令洞值为父值
    		holeIndex=parent;//调整洞号,向上提升至父节点
    		parent=(holeIndex-1)/2;//新洞的父节点
    	}//持续至顶端,或满足heap的次序特性为止
    	*(first+holdIndex)=value;//令洞值为新值,完成插入操作
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    pop_heap算法

    如图所示:
    在这里插入图片描述
    下面是pop_heap算法的实现细节

    template<class RandomAccessIterator,class Distance,class T>
    void _adjust_heap(RandomAccessIterator first,Distance holeIndex,Distance len,T value)
    {
    	Distance topIndex=holeIndex;
    	Distance secondChild=2*holeIndex+2;
    	while(secondChild<len)
    	{
    		//比较洞节点之左右两个子值,然后以secondChild代表大子节点
    		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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    注意,pop_heap之后,最大元素只是被置放于底部容器的最尾端,尚未被取走,如果要取其值,可使用底部容器(vector)所提供的back()操作函数,如果要移除它,可使用底部容器所提供的pop_back()的操作函数

  • 相关阅读:
    Spark RDD惰性计算的自主优化
    C++ Reference: Standard C++ Library reference: C Library: cmath: ceil
    软件测试的调用接口怎么调用,逻辑是什么?
    LigaAI X 猴子无限 | AIGC 火了,专业设计者的福音来了!
    2022属虎的双胞胎男宝名字 很不错的宝宝取名
    日常中出现msvcp140.dll丢失的5个解决方法与msvcp140.dll详细解析
    获取Stream流
    在多核异构SoC平台上进行软件开发
    背包问题汇总(01背包、完全背包、多重背包、分组背包)
    【WSN路由】异构无线传感器网络分布式节能分簇算法的设计(DEEC)附Matlab代码
  • 原文地址:https://blog.csdn.net/m0_51174487/article/details/125896509