白话经典算法系列之七 堆与堆排序

【机器学习—评估指标】混淆矩阵、准确率、精确率、召回率、F1分数、ROC曲线和AUC 机器学习评价指标是衡量模型性能的关键工具。本文介绍了常见指标及其计算方法:1.混淆矩阵展示分类预测结果分布,包含TP、TN、FP、FN四个基础指标;2.准确率反映整体预测正确率;3.精确率关注预测正例的准确性;4.召回率衡量正例检出能力;5.F1分数综合平衡精确率和召回率;6.ROC曲线通过TPR与FPR的权衡关系评估模型性能,AUC值量化区分能力。文章详细说明了各指标的定义、计算公式、适用场景及局限性,并通过Python代码示例演示了具体实现方法,特别对ROC曲线和AUC的计算原理进行了深入解析。 阅读详情

堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。


二叉堆的定义

二叉堆是完全二叉树或者是近似完全二叉树。

二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。下图展示一个最小堆:

由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。


堆的存储

一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。


堆的操作——插入删除

下面先给出《数据结构C++语言描述》中最小堆的建立插入删除的图解,再给出本人的实现代码,最好是先看明白图后再去看代码。


堆的插入

每次插入都是将新数据放在数组最后,可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于直接插入排序中将一个数据并入到有序区间中,对照《白话经典算法系列之二 直接插入排序的三种实现》不难写出插入一个新数据时堆的调整代码:

 // 插入后的重排序,a为新数组,k为新插入元素的下标   
 void MinHeapFixup(int a[], int k)
    {
         while (k > 1) {
            int j = (k -1) / 2; // 找到当前节点的父节点坐标
            if (a[j] < a[k])
                break;
            int tmp = a[j];  a[j] = a[k]; a[k] = tmp;
            k = j;
        }
    }

 


堆的删除

按定义,堆中每次都只能删除第0个数据。为了便于重建堆,实际的操作是将最后一个数据的值赋给根结点(这一步没有任何问题吧)。然后再从根结点开始进行一次从上向下的调整。调整时先在左右儿子结点中找最小的,如果父结点比这个最小的子结点还小说明不需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点将一个数据的“下沉”过程。

流程图,以序列{13,38,27,49,76,65,49,97}为例:

下面给出如何进行调整的代码:MinHeapFixdown将指定节点构造成堆结构,同时确保发生交换后仍然能保证子节点满足堆结构,以上图为例,将节点97及其子节点38,27构造成堆结构,首先交换97,27。在原先27的位置发生了交换变为了97,此时就要保证节点97及其子节点65,49仍满足堆结构,重复上述步骤,直至都满足堆结构。

    //  从i节点开始调整,n为节点总数 从0开始计算 i节点的子节点为 2*i+1, 2*i+2
    void MinHeapFixdown(int a[], int i, int n)
    {
        int j, temp;
     
        temp = a[i];
        j = 2 * i + 1;
        while (j < n)
        {
            if (j + 1 < n && a[j + 1] < a[j]) //在左右孩子中找最小的
                j++;
     
            if (a[j] >= temp)
                break;
     
            a[i] = a[j];     //把较小的子结点往上移动,替换它的父结点
            i = j;
            j = 2 * i + 1;
        }
        a[i] = temp;
    }



    //在最小堆中删除数
    void MinHeapDeleteNumber(int a[], int n)
    {
	    Swap(a[0], a[n - 1]);
	    MinHeapFixdown(a, 0, n - 1);
    }

 

堆化数组

有了堆的插入和删除后,再考虑下如何对一个数据进行堆化操作。要一个一个的从数组中取出数据来建立堆吧,不用!先看一个数组,如下图:

很明显,对于所有叶子结点来说,可以认为它已经是一个合法的堆了,不需要调整,即20,60, 65, 4, 19都分别是一个合法的堆。所以我们需要关注的只是非叶子节点,从下至上检查每一个非叶子节点是否符合堆结构。我们知道一棵完全二叉树的最后一个非叶子结点的索引为n/2 -1(n为总元素个数)

这里我们从最后一个非叶子节点A[4]=50开始向下调整就可以了。然后再取A[3]=30,A[2] = 17,A[1] = 12,A[0] = 9分别作一次向下调整操作MinHeapFixdown就可以了。下图展示了这些步骤:

PS:上图其实不太具有代表性,可能会让人产生一定误解。如果将原数组中12换成大于30的数,比如40,那么c图中,除了将40与4交换位置外,还要把40和30交换位置。即MinHeapFixdown操作除了构造指定节点为堆结构外,还要确保其子节点(以及子节点的子节点...整条线)也满足对堆结构的。

写出堆化数组的代码:

    //建立最小堆
    void MakeMinHeap(int a[], int n)
    {
        for (int i = n / 2 - 1; i >= 0; i--)
            MinHeapFixdown(a, i, n);
    }

至此,堆的操作就全部完成了,再来看下如何用堆这种数据结构来进行排序。


堆排序

将堆结构中的数据进行排序。

首先可以看到堆建好之后堆中第0个数据是堆中最小的数据。取出这个数据再执行下堆的删除操作。这样堆中第0个数据又是堆中最小的数据,重复上述步骤直至堆中只有一个数据时就直接取出这个数据。

由于堆也是用数组模拟的,故堆化数组后,第一次将A[0]与A[n - 1]交换,再对A[0…n-2]重新恢复堆。第二次将A[0]与A[n – 2]交换,再对A[0…n - 3]重新恢复堆,重复这样的操作直到A[0]与A[1]交换。由于每次都是将最小的数据并入到后面的有序区间,故操作完成后整个数组就有序了。有点类似于直接选择排序。

    void MinheapsortTodescendarray(int a[], int n)
    {
        for (int i = n - 1; i >= 1; i--)
        {
            Swap(a[i], a[0]);
            MinHeapFixdown(a, 0, i);
        }
    }

注意使用最小堆排序后是递减数组,要得到递增数组,可以使用最大堆。

由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)。STL也实现了堆的相关函数,可以参阅《STL系列之四 heap 堆》。


 

数据挖掘实战-基于LSTM时间序列模型的香烟销售预测分析 本文介绍了基于LSTM时间序列模型的香烟销售预测分析实验。实验背景为烟草市场竞争激烈,企业需提高销售预测准确性以优化生产、库存和营销策略。LSTM模型因其处理长序列数据的能力被选为预测工具。实验步骤包括数据准备、特征工程、模型构建、训练与评估及结果分析。数据集来自某市门店的销售数据,技术工具为Python 3.9和Jupyter Notebook。实验过程涵盖数据导入、预处理、产品销售与区域销售分析、销售预测(包括销售额、销量、利润及海通店销售额预测)。 阅读详情

相关推荐

操作系统课程项目 OS project —— Pintos from Project 1 to Project 3

Pintos Project 陪伴我们操作系统课程大半个学期了…… 虽然做了这么长时间,个人能力有限,pintos代码,看过的可能也就看懂了一半吧,更不用说没看过的了…… 但是也找到了一些有价值的资料,整理一下,供后辈们参考…… 关于环境的问题,最好是用ubuntu 16.04 windows用户不要折腾装双系统了,特别是win10,动不动更新一下,说不定双系统就出问题了,linux...

Deserted Land 8557

海量数据处理--外排序算法

外排序算法是指能够处理极大量数据的排序算法。通常来说,外排序处理的数据不能一次装入内存,只能放在读写较慢的外存储器(通常是硬盘)上。通常采用“排序-归并”的策略,将原本的大文件,拆分为若干个小文件,小文件可以读入内存中进行排序,然后使用归并操作。 因此,外排序通常分为两个基本步骤: 将大文件切分为若干个个小文件,并分别使用内存排好序 使用K路归并算法将若干个排好序的小文件合并到一个大文件中 接下来...

zztSky 775

PSCAD学习笔记(1)Project Settings(重点snapshot设置)

若不勾选,则横坐标为实际时间2-7s,故障显示在第3s发生。图片中时间坐标轴显示为0-5s,故障时刻显示为第1s,即0-1s展示系统稳态,1-5s展示系统发生故障后的暂态响应,如何通过快照文件实现?勾选该项后,使用快照文件启动仿真会将仿真起始时间强制设置为0s,反之不勾选则依据快照文件保存的时间轴继续(即坐标为实际时间)。如果已有的快照文件保存的是0s至5s的仿真内容,则仿真运行时间从5s开始,到10s结束。如果已有的快照文件保存的是0s至2s的仿真内容,则仿真运行时间从2s开始,到7s结束;

gwenh的博客 7348

【数据结构】 常见的八大排序算法

​排序有内部排序和外部排序,这里八大排序就是内部排序,指直接插入,希尔,选择,堆排,冒泡,快排,归并,计数。 附有动图解释和思维导图汇总

阿润菜菜的博客 1万+

c# 开发串口调试助手 Visual Studio 2019

串口调试助手是用于在开发、测试和调试串口通信应用程序时进行串口数据的监视和交互的工具。

2301_76792852的博客 8062

高速设计注意事项总结——MDI篇

在以太网高速通信系统中,MDI(Medium Dependent Interface,介质相关接口)是连接物理层芯片(PHY)与传输介质(如网线)的关键接口,其设计直接影响信号完整性、传输速率和抗干扰能力。本文围绕 MDI 及 RJ45 接口电路、关键参数、设计与布线要点展开,为高速以太网设计提供参考。本文包含MDI 及 RJ45 接口电路组成、电路设计注意事项、布局布线要求等内容

qq_16237389的博客 1454

排序算法-堆排序、归并排序、快速排序、外部排序

堆排序,归并排序,快速排序的优化,快速排序递归实现,快速排序非递归实现,算法四中的分区方法,挖坑法,三路快排,桶排序,基数排序,计数排序

qq_43243800的博客 856

5. SAP UI5 视图控制器(Controller)初探

本教程的前一个步骤也就是第四个步骤,我们了解了 SAP UI5 XML 视图的使用方法。在该步骤里,我们在 XML 视图里声明了一个 Text 控件实例,该控件位于 sap.m 这个命名空间内。 本步骤会继续接触 SAP UI5 MVC 框架中三大基石的另一块:C - Controller,即控制器。 先看看本步骤完成之后,我们得到的 SAP UI5 应用能实现一个什么样的效果。 访问如下 url: http://localhost:8080/webapp/index.html 能看到一个 Say Hell

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

外部排序和大小堆相关知识

它的插入和查询复杂度都是 log(n),可以说比较高效。不过,堆调整时,每个节点都需要和左右孩子进行比较,即需要两次比较,在外部排序中,也就是需要读取两次外存,那能不能再优化下呢? 于是,研究出了胜者树。胜者树只需要和兄弟节点进行比较,减少了一般的比较量。但是,胜者树还需要从父节点取一次值,并且,因为新插入的值取代了原先的最优胜者,这个新值向上调整的过程中,必定需要修改父节点的值,即必须要更新胜者。那能不能再优化呢? 既然有胜者树,那自然也有败者树。败者树解决了胜者树存在的弊端,只需要和父节点比较一次,

m0_60512979的博客 392

SAP CRP能力计划详细说明操作及相关配置

2、求助朋友同事的希望破灭后,网上找了资料发现在百度搜索的资料基本都是没有说明白什么才产能计划,都没有详细的操作说明,然后用google去搜索了一些相关的文章,好像也没有详细的文章。然后也去SAP的官网搜索了相关的文章,都是文字性的表述,对系统的配置都没有很大的帮助,很久之前有记得在隐身人的博客中有提到CRP的能力计划的文章,然后试着去找了一下相关的文章。5、首先产能排产肯定涉及的就是是能力的问题,能力第一个能想到的就是工作中心中的能力页签,在流程制造中也叫资源,其实都是一个东西。

我小时候很黑的博客 4523

2025年微信小程序获取手机号授权登录注册详细教程(含服务端)。不弹窗原因以及减少组件用量的方法

前端把获取到的code传给后端,后端获取access_token和前端传过来的code,请求服务器接口,即可获取到手机号。

coderYYY的博客 3万+

堆算法

1 基本概念 1.1 定义 堆是一种树状数据结构,它满足如下性质: 堆序性:任一节点值均小于(或大于)它的所有后代节点值,最小值节点(或最大值节点)在堆的根上。 结构性:堆总是一棵完全树,即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。 1 11 ...

pirlo-san的博客 2439

字节系,ali系,ks,pdd最新抓包方案

各大厂安卓逆向

qq_38759383的博客 1147

【转】白话经典算法系列之七 堆与堆排序

堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法。学习堆排序前,先讲解下什么是数据结构中的二叉堆。 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树。 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。 当父结点的键值总是大于或等于任...

110

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: lock学习笔记01
下一篇: 最小堆与最大堆测试代码
MrMoving
博客等级 码龄10年 54粉丝 145原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值