最大优先队列与堆

最大(小)堆 优先队列模板 本文参考于《啊哈!算法》,作者为纪磊。 最小堆 众所周知 ,堆是一颗完全二叉树,而堆主要用于辅助程序进行排序等操作,一般不会独立作为考试内容。 著名应用就是优先队列了等时间复杂度为(nlogn) 的排序操作,而且是从输入后,就已经排完序。 话说我怎么就记不住(priority queue)呢? 首先建树函数creat(); 从最后一个非叶节点的节点开始,依次向“上”进行向下调整。 因为完全二叉树的... 阅读详情

在《算法导论》中对队的介绍在第6章。堆排序的性能不是特别好,远远不如快速排序,但是在操作系统中的优先调度里面需要的优先队列结构中采用堆有着不错的性能。

堆

什么是堆?堆可以理解成一种特殊的树,这种树的结点永远大于它的子节点。如:

堆

第一眼看上去就是一颗普通的二叉树,其实仔细的看就会发现这棵树上的父节点永远大于他的子节点,这就是堆。

用数组来表示二叉树和堆

还是看上面那个图,这次主要看序号。
假设这棵树用数组来表示,那么数组的序号如图所示。
我们可以发现以下3条规则:

  1. 父节点是 (子节点-1)/2 如0 = (2 - 1) / 2
  2. 左节点是 父节点2+1 如1 = 0 2 + 1
  3. 右节点是 父节点2+2 如2 = 0 2 + 2
    上面的除法是指整除,现在我们就可以用数组来表示这个堆了。

堆排序

如果,使这颗树永远保持这个特性,那么可以轻松证明他的根节点是树中各节点中的最大值节点。取出这个节点,放在数组的最后一位(或者是第一位),然后让这颗树继续保持这种特性,然后重复取出节点,那么最后这个数组就是一个排好顺序的数组。
道理很简单,关键在于两个问题:
1. 如何在开始的时候,如何初始化这个堆?
2. 如何在取出一个节点后,如何依旧保证堆的特性呢?
把问题分解后,是不是感觉不是特别难了呢?
对于上面这两个问题,有一个很基本的问题就是保持堆的特性,一直在强调堆的特性,其实就是父节点一定要大于他的左右子节点,如何用代码来表示:

void swap(int *a,int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

// arr是堆数组,k是要保证第几个节点维持该特性,n代表该堆数组的大小
void keep_sort(int *arr,int k,int n)
{
    // k是否有左节点,如果没有左节点,那就肯定也没有右节点,不用比较,退出即可
    if(k * 2 + 1  >= n)
    {
        return;
    }
    // k是否大于左节点,为真则交换父节点与左节点,因为左节点发生改变(并且一定是变小)
    // 所以,左节点要与自己的子节点进行比较是否变得比自己的子节点还小
    if(arr[k * 2 + 1] > arr[k])
    {
        swap(&arr[k * 2 + 1],&arr[k]);
        heap_property(arr,k * 2 + 1,n);
    }
    // 同理,看看有没有右节点
    if(k * 2 + 2  >= n)
    {
        return;
    }
    // 同理,k是否大于右节点
    if(arr[k * 2 + 2] > arr[k])
    {
        swap(&arr[k * 2 + 2],&arr[k]);
        heap_property(arr,k * 2 + 2,n);
    }
}

基本的问题解决了,接下来要解决上面的两个问题了。

void heap_sort(int *arr,int n)
{
    // 初始化节点,因为从n / 2 - 1开始才有子节点,所以从n / 2 - 1开始初始化
    // 如果想证明,可以根据左节点的计算方式来证明(其实就是逆运算)
    for(int i = n / 2 - 1;i >= 0;i--)
    {
        keep_sort(arr,i,n);
    }
    for(int i = 1;i < n;i++)
    {
        // 把最大值(根节点,数组下标为0的值)与数组末尾的值交换
        swap(arr[n - i],arr[0]);
        // 现在根节点不再是最大值,所以根节点需要重新排序,数组末尾的值已排好序
        // 所以,不再进行排序,数组总数-1
        keep_sort(arr,0,arr[n - i]);
    }
}

PS:尽量保证可以看懂,但是有一些部分可能还是用了一些办法,不过都可以证明的
PPS:上次写代码时没有这么顺利的,这次莫名其妙感觉完全会了

优先队列

其实,堆排序的速度是远远比不上快速排序的,但是他也有他的价值,就是优先队列。优先队列在操作系统的任务调度中很重要,操作系统可以根据任务中的重要性来选择哪个任务先执行,也可以根据哪个任务执行的速度最快来选择执行(实际中现代操作系统要比较复杂,集合了很多种算法)。
队列的特点是先进先出,优先队列就是优先级最高的先出队(如最大优先队列则是数值最大的先出队)。使用堆来实现优先队列的话,优先队列开始为空,优先队列的入队操作只需要进行一次维护堆的特性就可以完成,而优先队列出队也只需要进行一次维护堆的特性就可以完成。

// 设置队列中的最大容量,其实也可以设计为容量可变的优先队列,但是不再这里写了
#define MAX 100
// keep_sort函数依旧使用上面那个
void keep_sort(int *arr,int k,int n);
// 交换两个值 
void swap(int *a,int *b)
// 设置队列存储的空间和当前存值的多少
int arr[MAX],n;
/*
 * 上面不是已经有一个keep_heap的函数了么?为什么还要再写一个keep_heap_up函数呢?
 * keep_heap函数是与子节点比较大小,如果比子节点小就要继续往下比较
 * 对于出队来讲很合适,因为改变的是根节点,所以直接与他的子节点比较就可以了
 * 但是对于入队操作来讲,我们只能把最新的值放到最后,那么对于keep_heap就不太适合了
 * 当然,如果你硬要用keep_heap来完成入队操作也是可以的,不过就要仿照初始化堆操作
 * 耗时太多了,我们为什么不再写一个专门为入队操作向上的keep_heap_up函数呢
*/
void keep_heap_up(int *arr,int n)
{
    // 如果n节点比他的父节点大,n节点与父节点交换,由于父节点的值改变并且是变大了
    // 所以,要把该节点与父节点的父节点进行比较 
    if(arr[n] > arr[(n - 1) / 2])
    {
        swap(&arr[n],&arr[(n - 1) / 2]);
        keep_heap_up(arr,n);
    }
}
// 返回队列最高优先级元素(最大值)
int top()
{
    //判断队列是否为空,不空返回根节点
    if(n == 0)
    {
        printf("Error,the queue is empty,output is invalid!");
        return 0;
    }
    return arr[0];
}
// 入队
void push(int v)
{
    if(n == 100)
    {
        printf("Error,the queue is full!");
        return;
    }
    arr[n++] = v;
    // 不可以用keep_heap,而是要用keep_heap_up
    keep_heap_up(arr,n);
}
// 出队
int pop()
{
    int result = 0;
    if(n == 0)
    {
        printf("Error,the queue is empty,output is invalid!");
        return 0;
    }
    swap(&arr[0],&arr[--n]);
    keep_heap(arr, 0, n);
    return result;
}

在《算法导论》书中其实是让写四种方法的,入队、出队、队列头以及改变队列中第X个的值。但是我没有写改变队列中某个值的方法,这是我认为如果说是为了学堆的特性他是有价值的,但是在实际应用中是毫无意义的,因为第X个值是不可控的。在堆中,我们只可以保证根节点是优先级最高的,但是第X个值在堆中排列第几或者有什么意义,我们都不得而知,所以懒得写了。其实如果写的话也很简单,无非就是改变这个值的大小,然后重新针对该值维护堆的特性。
PS:打个广告,我在码云上面最近开始了一个将《算法导论》中的伪代码算法写成C/C++语言的小开源项目。我知道关于《算法导论》中的伪代码写成C/C++的现成代码有很多,主要还是为加深下影像。我也知道《算法导论》里面的精髓不止这些,但这也无妨,我也没打算只看这一遍。我还知道我写的代码可能不是最优解、不是根据《算法导论》中的思想来解、甚至存在错误也是相当有可能的,有错误您提、不是最优解您也说,写出来就是交流的,您提出来特别感激,免得其他人看了我的博客误人,那就不好了(虽然现在博客访问量很少),再次拜谢。如果您也在看《算法导论》,我强烈建议您也开个项目做做,说实话这本书啃了好几次,就这次看的最多,啃的最深。
PPS:关于这一篇的代码地址:如果可以加星就可以更好了

36、弱堆优先队列与自然数最大和代数的等式理论 本文探讨了弱堆优先队列数据结构和自然数最大和代数的等式理论。在弱堆优先队列部分,介绍了插入和删除最大值等操作,分析了弱堆排序的性能,并与其他排序算法进行了比较,证明了其优越性。在自然数最大和代数方面,研究了其公理体系,并通过引入自由代数、序理想和凸理想等概念,证明了两个变量方程集合 $Eq2(N)$ 不存在有限公理化,同时阐述了最大和代数与幂等半环、热带半环等结构的联系与应用。 阅读详情

相关推荐

自动控制原理之控制系统的数学模型(类比神经网络学习数学模型)

控制系统的数学模型背景建模方法常用的数学模型时域数学模型的建立建立微分方程的步骤复数域模型的建立传递函数的性质系统的典型环节及传递函数比例环节惯性环节积分环节微分环节理想微分环节一阶微分环节二阶微分环节振荡环节延时环节(时滞环节) 背景 数学模型就像是真实世界的写照,它就像一个虚拟的世界,我们可以通过建模的方式了解这个真实世界的运作规律。 这一点很像强化学习,强化学习需要一个供智能体探索、学习的环境,于是,我们通常会事先建立一个虚拟的仿真环境。举个例子,对于人类来说,可能需要经过不断地尝试,甚至是生命的代价

zbp_12138的博客 6578

【数据结构与算法】第九章:优先队列(最大、最小、索引)

普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在某些情况下,可能需要找出队列中的最大值或者最小值 例如:使用一个队列保存计算机的任务,一般情况下计算机的任务都是有优先级的,需要在这些计算机的任务中找出优先级最高的任务先执行,执行完毕后就需要把这个任务从队列中移除。普通的队列要完成这样的功能,需要每次遍历队列中的所有元素,比较并找出最大值,效率不是很高,这个时候,就可以使用一种特殊的队列来完成这种需求,优先队列 优先队列按照其作用不同,可以分为以下两种: 最大优先队列: .

土味儿 1466

深入解析HAL_UART_Receive_IT:如何高效配置串口中断接收

本文深入解析了STM32 HAL库中`HAL_UART_Receive_IT`函数的工作原理与高效配置方法。该函数并非直接接收数据,而是作为中断接收的启动器和配置器,通过开启相关中断,由`UART_Receive_IT`在后台完成数据搬运。文章详细对比了中断与轮询模式的区别,并提供了不定长数据接收的完整实战流程、常见问题避坑指南及高级应用技巧,帮助开发者构建稳定高效的串口通信。

weixin_29162439的博客 636

优先队列(详解--最大优先队列,最小优先队列)

优先队列 普通的队列是一种先进先出的数据结构,元素在队列尾部追加,从而队列头删除。在某些情况下,我们可能需要找出队列中的最大值或者最小值,例如使用一个队列保存计算机的任务,一般情况下,计算机的任务都是有优先级的,我们需要在这些计算机的任务中找出优先级最高的任务先执行,执行完毕后就需要把这个任务从队列中移除。普通的队列要完成这样的功能,需要每次遍历队列中的所有元素,比较并找出最大值,效率不是很高,这......

qq_43751200的博客 8509

Cursor+Apifox MCP Server实战:5分钟搞定API自动化测试用例生成

本文详细介绍了如何利用Cursor IDE与Apifox MCP Server,在5分钟内将API文档自动转化为高质量的自动化测试用例。通过配置MCP Server建立数据桥梁,开发者可直接用自然语言指令,让AI基于真实接口规范生成可立即执行的pytest测试代码,大幅提升接口测试效率,特别适合快节奏的SaaS项目。

ooo22的博客 533

IIC协议常见误区解析:从时序图到实际波形(附逻辑分析仪实测)

本文深入解析IIC协议在实际应用中的常见误区,从理想时序图到逻辑分析仪实测波形的差异,揭示通信故障的根本原因。通过硬件设计优化、软件时序调优和高级调试技巧,帮助开发者有效规避IIC通信中的隐形陷阱,提升系统稳定性。

weixin_28738397的博客 370

数据结构——队列、最大堆、优先级队列

队列是一种只允许在一端进行插入操作,而在另一端进行删除操作的线性表。队列,顾名思义,就好像我们在超市结账排队一样,先排进队的人先买单,先进入队列里的元素先出队,也就是 先进先出的特点(First In First Out,FIFO),允许插入元素的一端称为队尾,允许删除元素的一端称为队首。

Se_ren_di_pity的博客 1914

从‘最速控制’到代码:深入拆解韩京清ADRC中TD跟踪器的fhan函数(含Matlab/Simulink实例)

本文深入解析韩京清ADRC中的fhan函数,从理论到代码实现,详细拆解其在Matlab/Simulink中的应用。通过分析最速控制问题和非线性TD的连续形式,揭示fhan函数在信号处理和噪声抑制中的独特优势,并提供工程实践中的参数整定和优化技巧。

weixin_42659194的博客 247

【原创】优先队列 priority_queue 详解

c++ 的 stl 里的 优先队列 priority_queue 的声明和基本操作

致上 19万+

Vivado固化程序与Flash型号添加实战指南

本文详细介绍了Vivado程序固化到Flash芯片的完整流程,包括基础操作、Flash型号添加方法及疑难问题排查。针对Vivado官方支持列表缺失的Flash型号,提供了手动添加配置的详细步骤和参数说明,并分享了高级技巧与安全操作建议,帮助开发者高效完成FPGA程序固化。

weixin_29291573的博客 566

SuperPoint + LightGlue实战:低纹理墙面重建保姆级教程(附完整代码)

本文提供了一份针对低纹理墙面三维重建的实战教程。通过详细解析SuperPoint与LightGlue的核心参数调优,指导读者如何有效提取并匹配低纹理目标的特征点,并结合COLMAP完成从稀疏到稠密的重建流程,最终实现高精度建模。

weixin_29034963的博客 223

最大优先队列

最大优先队列前言    堆排序是一种集插入排序和选择排序的有点于一身的排序算法,但是在后面能学习到更加好的快速排序算法,性能优于堆排序。堆这钟数据结构还有许多其他的用处,例如作为高效的优先队列。优先队列分为最大优先队列和最小优先队列,今天学习了如何用最大堆来实现最大优先队列。    优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,称为关键字。一个最大优先队列

凹凸曼哒小乖兽 1980

破盾实录|Vueling航空阿卡迈防护逆向:从503挑战到Cookie生成的全流程拆解

摘要:文章分享了作者在爬取西班牙伏林航空(Vueling)机票数据时,遭遇阿卡迈(Akamai)防护系统的实战经历。起初简单的请求被拦截返回503错误,分析发现阿卡迈通过混淆JS代码实施"挑战-验证"机制,需模拟真实浏览器环境才能获取有效Cookie。作者详细拆解了逆向过程:从抓包分析JS挑战流程,到破解代码混淆和控制流平坦化,最终用Python+Pyppeteer成功模拟浏览器特征,突破防护获取数据。整个过程涉及JS反混淆、环境检测绕过和Cookie生成验证等关键技术点,为类似防护系统

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1643

优先队列、最小堆、最大堆

其实排列顺序就是从上到下,从左到右进行排列,例如{1,2,3,4,5,6,7},看第一张图就是按照顺序进行排列,当然对照下面公式也可以来做,例如 1 的索引为0,要确定它的左子节点就是 0* 2 +1 = 1,也就是索引1,对应元素值2,同理右子节点就是 0*2+2=2,索引2也就是元素值3.这样,对于下标为i的节点,其左子节点的下标为2i,右子节点的下标为2i+1,而其父节点的下标为i/2。对应的数组为[10, 20, 15, 30, 40],符合小顶堆的定义,即每个节点的值都小于或等于其子节点的值。

m0_64132144的博客 997

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Java 基于堆的最大最小优先队列

优先队列 解释: 在程序中需要有序的处理一批程序,但一定要求它们全部有序,或者是不一定要一次就将它们排序; 很多情况都是收集一些元素,然后处理最大/最小元素,也就是应该支持删除最大/最小元素和插入元素的一种数据结构。 定义: 优先队列是一种抽象数据类型(能对使用者隐藏数据类型),它表示了一组值和对这些值的操作,它的抽象层能使我们方便的将我们的应用程序和我们的具体实现分离开来 堆 堆可以理解为是一种...

Ich warte auf dich的博客 1328

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

优先队列(Priority Queue)最大堆最小堆

建议读者先去下载《啊哈算法》看大概在P182页的堆,什么是最小堆? ps:如果想进来学习什么是堆的童鞋们,你们不需要再继续往下面阅读啦,对你们有意义的是第一行哦~随后我将此本算法书会长传到csdn上哦~ 而已经学习过数据结构,对堆已经有了初步认识的童鞋,可以仔细读读一下内容哦,以下主要是堆的应用。以及为什么要用堆~ 最小堆就是 所有的父节点都要比子节点要小,反之所有的父节点都要比子节点大的完...

李静静 1万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

堆(优先队列,即最大堆,最小堆)

堆: 优先队列(Priority Queue):特殊的“队列”,取出元素的顺序是 依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序。 堆的两个特性 : 结构性:用数组表示的完全二叉树; 有序性:任一结点的关键字是其子树所有结点的最大值(或最小值) “最大堆(MaxHeap)”,也称“大顶堆”:最大值 “最小堆(MinHeap)”,也称“小顶堆” :最小值 下面以最大堆(数组实现)为例,...

Running ╯的博客 798

优先队列--最大、最小优先队列(基于堆思想)

优先队列–最大优先队列(基于堆思想) 最大优先队列:可以获取并删除队列中最大的值 最大优先队列API设计 类名 MaxPriorityQueue 构造方法 MaxPriorityQueue(int capacity):创建容量为capacity的MaxPriorityQueue对象 成员方法 1.private boolean less(int i,int j):判断堆中索引i处的元素是否小于索引j处的元素2.private void exch(int i,int j):交换堆中i索引和

一名小白的博客 468

【数据结构笔记15】优先队列、堆、最大堆、堆的操作(插入、删除、建立)与C实现

由优先队列概念引出堆的概念,堆的删除中提到“向下过滤”思想。

记录学习痕迹的公众号:Piper蛋窝 1344

算法导论 总结 - 优先队列、最大堆、最小堆及堆排序

1、完全二叉树:若二叉树的深度为h,则除第h层外,其他层的结点全部达到最大值(都是满的),且第h层的所有结点都集中在左子树。 2、满二叉树:满二叉树是一种特殊的的完全二叉树,所有层的结点都是充满的。 堆是一棵完全二叉树。最大堆:父节点都大于等于子节点,根最大;最小堆:子节点都大于等于父节点,根最小。 堆排序中使用的是最大堆,最小堆通常用于构造优先队列。 维护堆的性质: MAX-HEAPIFY 输入是一个数组A和一个下标i,维持最大堆逐级下降。从上往下,从左往右,把根和左结点,右结点的最大值找出来,与根交

RUN 1496

STL中优先队列(堆)和自定义最大堆最小堆

STL中优先队列(堆)和自定义最大堆最小堆引言最大堆的一个例子最小堆的一个例子 引言 在算法实践中,有的算法要求不停地插入或移除最大或最小值。若用线性比较,则时间复杂度为O(n2n^2n2)。这时候,若用优先队列,则可有效降低时间复杂度。优先队列又称为堆。它的复杂度为O(logN). 当N比较大时,能够有效降低计算时间。优先队列可以用数组自己实现。若对自己的实现没有把握,则可用STL自带的模板。不...

zhanghuineu的博客 1096

优先队列:最大优先队列、最小优先队列(堆实现)

目录0 优先队列1 最大优先队列2 最小优先队列 0 优先队列 普通队列先进先出,队尾加,队头删; 某些情况下,我们需要找出队列中的最大值或最小值。比如使用一个队列保存计算机的任务,任务需要有优先级,我们需要找出优先级最高的任务先执行,执行完毕后将任务从队列删除。 普通队列完成任务,需要遍历队列所有元素,比较并找出最大值,效率低下; 这时可以使用一种特殊的队列来完成需求,即优先队列。 按照功能需求分两种:1 最大优先队列:获取并删除队列中最大的值;2 最小优先队列:获取并删除队列中最小的值。 1 最大优

sc179的博客 1549

最大堆与最小堆与优先队列

堆的定义及其实现 最小堆:最小堆是一个关键码序列{ K0,K1,...Kn-1},它具有如下特性: Ki ≤K2i+1 Ki≤K2i十2 类似可以定义最大堆 堆的性质 可以看出是完全二叉树 堆中的数据是局部有序的,堆不唯一 兄弟节点之间没有限制 从逻辑结构来看堆实际上是树形结构 最小堆的类定义(ADT) template &lt;class T&gt; class MinHeap {...

weixin_34034261的博客 417

LeetCode:215 数组中第k个最大元素 优先队列 / 堆

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 来源:力扣(LeetCode) 链接:...

AKGWSB 's blog 369

数据结构学习之——最大堆、最小堆(优先队列、哈夫曼树)

最大堆、最小堆(优先队列、哈夫曼树完整版)最大堆(优先队列)最大堆(优先队列)的生成最大堆(优先队列)的删除最大堆(优先队列)的插入哈夫曼树 最大堆(优先队列) 最大堆:根结点的键值是所有堆结点键值中最大者,且每个结点的值都比其孩子的值大。 最小堆:根结点的键值是所有堆结点键值中最小者,且每个结点的值都比其孩子的值小。 最大堆(优先队列)的生成 生成最大堆:最大堆通常都是一棵完全二叉树,因此我们使...

还是有明天丶 2615

C++优先队列/priority_queue(最大堆、最小堆)

定义: priority_queue<int,vector,less> q;最大堆(默认为最大堆) priority_queue<int,vector,greater> q;最小堆 Priority queues are a type of container adaptors, specifically designed such that its first eleme...

geter_CS的博客 2万+
上一篇: Java日期时间字符串、Date和长整型毫秒Unix时间戳之间的转换
下一篇: 使用FFMPEG进行音视频编解码(C++) 0.简介
dutong0321
博客等级 码龄15年 62粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值