优先队列(堆)

C++实现优先队列——最小堆,d路堆及配对堆 C++实现三种优先队列 阅读详情

优先队列

和队列一样优先队列也支持入队和出队操作,不过区别在于优先队列的出队操作出队的是优先级最高的元素,这里以元素的大小来判定任务的优先级,越小,优先级越高。优先队列的模型如下图:

                 

基于这种优先队列的模型,我们可以多种方法对其进行实现,一种常用的方法就是使用链表以O(1)执行 插入操作,,遍历最小元素并删除花费O(N)时间。基于优先队列的插入操作一般情况下多于删除操作这一情况, 前者是一种较好的实现。


 二叉堆

二叉堆就结构性质上来说就是一个完全填满的二叉树,满足结构性和堆序性。结构性不必多说,就是完全二叉树应该满足的树结构。堆序性指的是:父节点的键值总是大于或等于(小于或等于)任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

最大堆:当父节点的键值总是大于或等于任何一个子节点的键值。

最小堆:当父节点的键值总是小于或等于任何一个子节点的键值。

                     

结构性质

上面对二叉堆的结构性质略有提及,这里我们进行下详细说明。看看二叉堆是如何实现的。

                  

仔细观察上述完全二叉树的结构,我们可以发现的是对于任意一个位置i,其结点的左孩子在2i的位置,右孩子在2i+1的位置上,基于上述的性质我们可以使用数组来实现二叉堆。 如下图,堆大小的界限是13个元素。该数组有一个位置0。

           

由此,二叉堆可以使用一个数组和一个代表当前堆的大小的整数组成。如下所示为一个优先队列接口:

template <typename Comparable>
class BinaryHeap
{
    public:
		explicit BinaryHeap ( int capacity = 100 );
		explicit BinaryHeap ( const vector<Comparable> & items );
		
		bool isEmpty () const;
		const Comparable & findMin() const;

		void insert ( const Comparable & x);
		void deleteMin ();
		void deleteMin( Comparable & minItem);
		void makeEmpty ();

	private:
		int currentSize; // Number of elements in heap
		vector<Comparable> array; //The heap array;

		void buildHeap();
		void percolateDown( int hole );
} 

以上代码显示的是一个优先队列的架构。至于其提供的具体操作,我们先看看二叉堆的堆序性。

堆序性

    简单的说保证优先队列的删除操作快速执行是堆序性质,基于这个特点我们需要找出最小元素,那么最小元素应该在根结点上,也就是最小堆。这样我们就能以常数时间执行 findMin()操作了。

二叉堆基本操作

基于二叉堆的堆序性,我们来看看二叉堆基本操作是如何实现的吧!

 insert(插入)

根据优先队列的模型,二叉堆实现的优先队列应该具备插入操作,不过根据其对序性具体的插入操作是如何进行的呢?看下面的演示:二叉堆插入元素14的情况。

              

                  

            

为将一个元素 X 插入到堆中,我们在下一个可用位置创建一个空穴,否则该堆将不是完全数。如果 X 可以放在该空穴中而不破坏堆的序,那么插入完成。否则,我们把空穴的父节点上的元素移入该空穴中,这样,空穴就朝着根的方向上冒一步。继续改过程直到 X 能被放入空穴中为止。这种实现过程称之为上滤(percolate up):新元素在堆中上滤直到找出正确的插入位置。

实现代码: 

/*
 * Insert item x, allowing duplicates.
*/

void insert (const Comparable & x)
{
	if (currentSize == array.size() - 1)
	{
		array.resize( array.size() * 2 );
	}

	// Percolate up
	int hole = ++currentSize;
	for (; hole >1 && x < array[hole / 2]; hole /= 2)
	{
		array [hole] = array [hole / 2];
	}
	array [hole] = x;
}
可以知道的是当插入的元素小于堆中所有的元素的时候,必须上滤到根,插入时间为O(logN)

deleteMin(删除最小元)

当删除一个最小元时,要在根节点建立一个空穴。由于现在堆少了一个元素,因此堆中最后一个元素 X 必须移动到该堆的某个地方。如果 X 可以直接被放到空穴中,那么 deleteMin 完成。不过这一般不太可能,因此我们将空穴的两个儿子中比较小者移入空穴,这样就把空穴向下推了一层。重复该步骤直到 X 可以被放入空穴中。因此,我们的做法是将 X 置入沿着从根开始包含最小儿子的一条路径上的一个正确的位置。

演示过程如下:

                 

首先我们删除根元素13,建立一个空穴,之后判断元素31是否可以放入这个空穴中, 明显不能, 会破坏堆序性.

                  

之后我们选择较小的左儿子放入空穴,同时空穴下滑一层,之后判断31是否置于空穴中

               

同上,26置于空穴中,空穴下滑一层,31可以置于空穴中,过程结束。 这一种操作过程称之为下滤(percolate down):空穴一步步下滑.

源码实现:

/*
* Remove the minimum item.
*/
void deleteMin( )
{
	if( isEmpty( ) )
		throw UnderflowException( );

    array[ 1 ] = array[ currentSize-- ];
    percolateDown( 1 );
}


/*
* Remove the minimum item and place it in minItem.
*/
void deleteMin( Comparable & minItem )
{
	if( isEmpty( ) )
		throw UnderflowException( );
	
	minItem = array[ 1 ];
    array[ 1 ] = array[ currentSize-- ];
    percolateDown( 1 );
}

/*
* Internal method to percolate down in the heap.
* hole is the index at which the percolate begins.
*/
void percolateDown( int hole )
{
	int child;
	Comparable tmp = array[ hole ];

	for( ; hole * 2 <= currentSize; hole = child )
	{
		child = hole * 2;
		if( child != currentSize && array[ child + 1 ] < array[ child ] )
		{
			child++;
		}
		if( array[ child ] < tmp < 0 )
		{
			array[ hole ] = array[ child ];
		}
		else
		{
			break;
		}
	}
	array[ hole ] = tmp;
}

优先队列其他操作

上面对二叉堆实现的优先队列的两个基本操作做了一些讲解。我们知道的是在将任务提交给优先队列的时候有时候我们需要根据实际情况修改任务的优先级。

  decreaseKey(降低关键字的值)

desreaseKey(p,m)操作降低在位置p处的值,降值幅度为正m,不过这种方式很可能破坏堆序性,因此需要通过上滤操作进行调整。这种方式能够动态的提高某个任务的优先级,使其在能够优先开始。 

increaseKey(降低关键字的值)

与上个操作相反,降低任务的优先级。

remove(删除)

remove(p)操作删除堆中位置p上的结点。这通过先先执行decreasekey(P,+ ∞),然后执行deleteMin() 操作。这种操作的任务并不是正常终止的,而是被用户终止的。

构造二叉堆

上述讲了二叉堆的方式实现优先队列。那么一个二叉堆又是如何构造的呢?简单的我们可以认为它可以使用N个相继的insert操作来完成。每个insert操作都花费O(1)的平均时间以及最坏时间为O(logN),所以则其构建为O(N)平均时间,其最坏情形时间为O(N*logN)。

更为常用的算法是先将N项以任意顺序放入树中,保持其结构性,之后再通过检查每个位置,通过下滤操作percolateDown(i) 使其满足堆序性。

        具体实现如下:

explicit BinaryHeap( const vector<Comparable> & items )
	: array ( items.size() + 10 ), currentSize (items.size() )  
	// set the size of array is items.size()+10, 
	// and set the number of elements (currentSize) is items.size()
{
	for( int i = 0; i < items.size(); i++ )
	{
		array[ i + 1 ] = item [ i ];  // copy from item[] to array[];
	}
	buildHeap();
}

void buildHeap()
{
	for( int i = currentSize / 2; i > 0; i-- )
		percolateDown( i );
}


优先队列-堆 优先队列  队列是一个操作受限的线性表,数据只能在一端进入,另一端出来,具有先进先出的性质。有时在队列中需要处理优先级的情况,即后面进入的数据需要提前出来,这里就需要优先队列。优先队列是至少能够提供插入和删除最小值这两种操作的数据结构。对应于队列的操作,插入相当于入队,删除最小相当于出队。   链表,二叉查找树,都可以提供插入和删除最小这两种操作。对于链表的实现,插入需要O(1),删除最小需要遍历 阅读详情

相关推荐

图解算法:堆、堆排序、优先队列

堆、堆排序、优先队列可以看成就是一个东西;堆是一种非常重要的数据结构,堆排序是基于堆这种数据结构实现的;优先队列可以用堆这种数据结构来实现,也可以用其他数据结构实现。优先队列可以用来实现有优先级的任务调用(一些任务在池子里等待,优先级最高的先被优先取出执行)

zfj321的博客 1427

优先队列---堆

在多用户环境中,操作系统调度程序必须决定在若干进程中运行哪个进程。一般一个进程只能被允许运行一个固定的时间片。一种算法是使用队列。开始时作业被放到队列的末尾。调度程序将反复提取队列中的第一个作业并运行它,直到运行完毕或者该作业的时间片用完,若作业未被运行完毕就将其放到队列的末尾。这种策略一般并不太合适,因为一些很短的作业由于一味等待运行而要花费很长的时间去处理。一般说来,短的作业要尽可能快地结束,。此外,有些作业虽不短小但很重要,也应该拥有优先权。所以提出啦优先队列。

qq_62309585的博客 565

堆——优先队列的实现

用数组表示的完全二叉树,堆是一种常用来实现优先队列的树形数据结构。堆通常以树形结构组织元素,但使用数组来存储这些元素。这种方法可以高效地管理完全二叉树的结构。以下是一个更详细的解释以及如何在C语言中实现这个概念。

码明的博客 931

二叉堆中上滤和下滤的问题

在学习到堆排序时,对于上滤和下滤的知识掌握的不清楚,回来复习了一下。有了些感悟,记下来。 上滤(percolate up) 上滤一般应用于在一个已经排序好的二叉堆中插入一个新节点。通过上滤,使堆在容纳了新节点后仍能保持原来的堆序。 上滤的主要思想: 首先在堆末新建一个空间,称为空穴(hole),然后比较穴的值和其父节点的值。如果空穴的当前位置满足整个堆的堆序,那么就把要插入的值赋给空穴

DragonBark的博客 4436

X光安检模型训练第一步:手把手教你处理OPIXray和HIXray这两个小众数据集

本文详细解析了X光安检AI模型训练的关键步骤,重点介绍如何处理OPIXray和HIXray这两个专业数据集。从数据格式转换到YOLO标准,再到数据增强和质量验证,手把手指导开发者高效利用这些数据集进行目标检测模型训练,提升安检场景下的危险物品识别准确率。

weixin_32629853的博客 316

机器学习篇-KNN算法实现鸢尾花模型和手写数字识别模型

一个样本最相似的k个样本中的大多数属于某一个类别, 则该样本也属于这个类别类似于: 近朱者赤近墨者黑回归机器建模流程:数据获取数据基本处理(空值和非法值)特征工程(特征提取, 特征预处理(归一化, 标准化), 特征降维, 特征选择, 特征组合)模型训练模型预测模型评估# 1. 定义函数 dm01_load_iris(), 用于加载 鸢尾花数据集, 并简单查看下数据集的各部分.# 1. 加载数据集.​# 2. 打印iris_data, 发现其实是1个: 字典.​。

m0_60916732的博客 2404

最大-最小堆

/**收获及心得 1.熟悉了二叉堆的class,并将其改为了升级版的最大-最小二叉堆 2.学会了声明,定义以及使用友元 3.对vector有了更深的理解 4.percolate down函数的算法断断续续写了四五天才大概满足次二叉堆的性质,收获蛮多 5.至于本次程序是为完成书上P187 6.18的练习题 ***遗留下的问题 1.merge函数还未完成,

yzu_120702117的专栏 713

用友U8其中一个账套提示演示期已到期-修复方法

【事件始末】 一朋友求助,反馈使用的用友U8,很多年了! 突然发现其中账套2021年的一个账套打不开,提示演示期限已到期! 但是其他账套完全正常,可以打开,没有任何问题。 不管是还原老旧备份,还是重装软件问题依旧,无法自己解决。 客户查询报表结算账期,情况比较紧急,于是求助我们。 经过多次反复琢磨和烟酒,终于于晚上23点59分给弄了出来,也总是圆满解决问题了。 【问题分析】 该用户打的是 U82X免狗补丁,估计是该补丁文件设置了 最大有效期,补丁到期了导致的。 也有可能是程序...

u010431289的博客 2万+

堆和堆排序

1、(二叉)堆可以使用一个数组实现,在逻辑上,我们可以将这个数组实现成一个完全二叉树。因为完全二叉树的父节点和孩子节点之间存在关系。例子如下:                             图a中就是一棵完全二叉树,并且这个完全二叉树是一个二叉最大堆(max堆)结构。因为该完全二叉树所有节点都满足堆序性。图b是该最大堆在内存上的存储形式,即以数组的形式存储,可以通过数组下标来实现其逻...

J_H_C的博客 422

图解说明JLink驱动与目标板电源匹配的关键细节

深入讲解JLink驱动安装及使用过程中,如何正确匹配目标板电源,避免常见通信故障。通过图解方式清晰展示关键连接细节,确保调试稳定可靠,是嵌入式开发中不可或缺的实战经验分享。

weixin_42173218的博客 431

Android 集成 Google 与 Facebook 第三方登录实战详解(2024版)

本文详细介绍了2024年Android应用集成Google与Facebook第三方登录的完整实战指南。通过分步教程和代码示例,帮助开发者快速实现一键登录功能,提升用户体验和注册转化率,同时涵盖隐私合规和常见错误处理的最佳实践。

blue的专栏 822

优先队列和堆

什么是优先队列? 听这个名字就能知道,优先队列也是一种队列,只不过不同的是,优先队列的出队顺序是按照优先级来的;在有些情况下,可能需要找到元素集合中的最小或者最大元素,可以利用优先队列ADT(Abstract Data Type)来完成操作,优先队列ADT是一种数据结构,它支持插入和删除最小值操作(返回并删除最小元素)或删除最大值操作(返回并删除最大元素); 这些操作等价于队列的enQueue和deQueue操作,区别在于,对于优先队列,元素进入队列的顺序可能与其被操作的顺序不同,作业调度是优先队列的一个应

数据工匠记 1257

生成模型实战 | StyleGAN详解与实现

StyleGAN 能够生成非常高分辨率人脸图像的关键在于,在增加分辨率的步骤中逐步增加生成网络和判别网络的复杂性,以便在每一步中,两个模型都可以很好地完成任务。我们学习了如何通过确保每个分辨率的特征由一个独立的输入(称为风格向量)来控制,从而操纵生成图像的风格,以及如何通过将图像之间的风格进行交换来操作不同图像的风格。

盼小辉丶的博客 7629

Python的堆与优先队列

Python的堆与优先队列 堆与优先队列 堆(英语:Heap)是计算机科学中的一种特别的树状数据结构。堆有如下特点:给定堆中任意节点P和C,若P是C的母节点,那么P的值会小于等于(或大于等于)C的值”。 按照母节点与子结点的大小关系,堆又可以分为以下两种:若母节点的值恒小于等于子节点的值,此堆称为最小堆(min heap);反之,若母节点的值恒大于等于子节点的值,此堆称为最大堆(max heap)。 在堆中最顶端的那一个节点,称作根节点(root node),根节点本身没有母节点(parent node)。

weixin_46302487的博客 767

什么是DHCP Snooping?如何配置DHCP Snooping?

功能描述防护类型防御伪造 DHCP 服务器、避免地址冲突、增强网络安全性使用场景企业园区网、校园网、大型局域网配合机制IP Source Guard、DAI、防止 ARP 欺骗部署难度⭐⭐(简单)“DHCP Snooping,是内网 DHCP 安全防护的第一道门神。” 🛡️。

网络技术联盟站 1267

在 ABAP CDS View 里把 Conversion Functions 用到极致:FLTP 精度、单位换算、货币换算与小数位处理的工程化实践

数据格式转换在真实项目中比业务逻辑更容易引发问题。ABAP CDS中的转换函数(如FLTP_TO_DEC、UNIT_CONVERSION、CURRENCY_CONVERSION和DECIMAL_SHIFT)可帮助在数据库层统一数据口径,避免应用层重复处理。这些函数支持数值精度治理、单位换算、货币转换和小数位调整,能显著提升报表性能并减少逻辑分散。通过将格式转换前移到数据模型层,可以确保服务层和UI层的数据一致性,同时降低接口传输错误风险。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2352

Dijkstra算法堆/优先队列优化

Dijkstra算法堆/优先队列优化前言额外知识简介堆与优先队列STL库重载Dijkstra分析及优化分析优化代码实现存储结构边点优先队列函数初始化添加边Dijkstra主函数后记 前文:Dijkstra算法&&邻接表数组 前言 ​ 1、本文中所采用的存储结构依然是邻接表数组,只是较上一篇文章中的结构稍微发生了一些变化,但本质是一样的,若不懂可参考前文; ​ 2、本文将涉及到堆...

Mark-2000的博客 6818

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

堆、堆排序、优先队列

文章目录堆1 (二叉)堆2 二叉堆的两种形式3 维护堆的性质4 建堆5 堆排序6 优先队列6.1 最大值(MAXIMUMMAXIMUMMAXIMUM)6.2 返回并弹出最大值(EXTRACT−MAXEXTRACT-MAXEXTRACT−MAX)6.3 增大关键字(INCREASE−KEYINCREASE-KEYINCREASE−KEY)6.4 插入(INSERTINSERTINSERT)6.5 优...

qq_39378221的博客 617

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

优先队列与堆

优先队列与堆 优先队列与堆 一 优先队列 1.1 定义 1.2 API 1.3 实现 二 堆 2.1 定义 2.2 表示 2.3 堆的有序化 2.4 基于堆的优先队列 一 优先队列 1.1 定义 在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。最简单的一个例子就是,在手机上玩游戏的时候,如果有...

能能 1333

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

基于堆的优先队列实现

基于堆的优先队列实现 优先队列严格说实际上不是一种队列,因为它并不需要遵循队列的FIFO特性,而要求的基本操作包括:向队列中插入新的记录,以及移出队列中的最大的元素。我们可以以各种不同的方式来实现优先队列——只要能够满足上面的两个接口就可以了。但是基于堆的优先队列则具有较好的性能。 优先队列是一种很有用的数据结构,因为实际上我们不是每时每刻都需要对数据进行严格的排序,有时候我们仅仅...

banyi4389的博客 119

优先队列,堆

普通的数据结构,如果我们想要寻找所存元素中的最大值或者最小值,需要挨个查找。而本章所学的优先队列和堆会按照优先级给元素排序,帮助我们以最快的速度O(1)获取优先级最高的元素。 优先队列 优先队列把优先级最高的元素设为链表的头节点,这样我们获取或删除优先级最高的元素只需要O(1)的时间复杂度,这么设计的代价就是牺牲插入的效率,每次插入一个新的元素时,我们都需要迭代链表,并找到合适的地方插入,这个时间复杂度往往是O(n)。 以下是优先队列支持的操作: push:插入一个新的元素 pop:将优先级最高的元素弹出

weixin_38384296的博客 855

用堆实现优先队列

 优先队列不同于普通队列采用先进先出的队列元素存取方式。插入队列元素时按照一定的规则插入,每次都是取队列中优先级最高的元素。可以采用最大堆来实现优先队列。堆是一颗完全二叉树,每个结点有一个权。它的特点是根结点的权值最大,且根的两个子树也各是一个堆。可以用数组来模拟堆。堆的操作有两种: (1)插入:方法是将新的元素i插到当前数组最后一个元素的下一个位置,然后对i进行上升调整。当i比它的父亲大

2532

堆实现优先队列

堆实现 为什么要使用堆实现优先队列? 在前面讲了用链队实现优先队列,其思想是插入元素时按普通队列入队,在删除元素(出队)时按优先队列的性质删除.那么就还有一种方式,即插入元素时按优先队列的方式插入,删除时按普通顺序队列的方式删除.那就是用堆实现优先队列! 由于前面已经写过堆的实现,这里不再重复造轮子,读者可以自己改写实现优先队列,我们使用容器适配器.堆的实现 首先我们需要一个容器,vector容器...

qq_40950183的博客 842

优先队列(堆)

这里写自定义目录标题场景功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 #用堆实现优先队列 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解

qq_44234405的博客 1555

堆———优先队列

1)大顶堆(默认):priority_queue 队列名;q.push(x);q.empty()即不空)O(1)(1)大顶堆:根结点最大,每个节点的值大于等于其孩子节点,用于升序(小->大)排列。(2)小顶堆:根结点最小,每个节点的值小于等于其孩子节点,用于降序(大->小)排列。(1) 无论入堆顺序,每次都是当前最大/小的元素(即堆顶元素)出队。2)若左子树结点个数len+1==x,则第x小的数即为当前根结点。2)出队(堆):将根结点出队,再将最后1个结点放到根结点位置,

soraaug的博客 230
上一篇: AVL树的插入和删除
下一篇: 最大堆(max-heap)和最小堆(min-heap)
Tim_WT
博客等级 码龄20年 2粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值