堆的应用

news/2024/9/19 14:15:42/文章来源:https://www.cnblogs.com/madadam/p/18411128

1.需要具备的知识

1.1以顺序存储方式存储完全二叉树

完全二叉树:节点从上到下,从左到右布局的二叉树,如下图所示。


完全二叉树可以使用类似数组这种顺序存储的结构存节点,如下图。


按照"层级遍历"方式遍历这棵树(还有"前序、中序、后序"遍历方式,这里不做介绍),遍历结果"10->5->1->2->3->6"保存到数组中。为了方便计算父子节点对应关系,不使用数组第一个元素。
如果一个节点在数组中的下标是curIdx,那么如果存在,其对应的左右孩子节点下标lcIdx,rcIdx,以及对应的父节点下标pIdx分别为:

lcIdx=2*curIdx;
rcIdx=2*curIdx;
pIdx=curIdx/2;

1.2堆介绍

堆是一种特殊的完全二叉树,分为大顶堆和小顶堆。大顶堆满足每个节点的值都大于或等于其孩子节点的值;小顶堆满足每个节点的值都小于或等于其孩子节点的值。如下图所示,以下部分我们全部以大顶堆为例

1.3堆化和建堆

堆化是指将某一个节点放到正确的位置,使得这个节点满足堆的属性。分为两种方式:从下向上堆化和从上向下堆化。

1.3.1从下向上堆化

使用场景是将元素一个一个插入到堆中,先将新元素做为叶子节点放到最后位置,然后将该节点向上堆化,最终落到满足堆特性的位置,如下图所示。
1.新节点值为9,先放入到最后位置。
2.9大于其父节点8,交换两个节点。
3.新的9节点继续和其父节点比较,小于10,堆化结束。

代码实现如下,nums存储的是堆节点数据。

//从下往上堆化一个节点
void HeapifyFromBToUp(vector<int>&nums,int heapIdx)
{while(heapIdx>1) //heapIdx为1的根节点没有父节点,故不用再处理{if(nums[heapIdx]>nums[heapIdx/2])//当前堆化节点的值大于其父节点的值{//交换两个节点的值int temp = nums[heapIdx/2];nums[heapIdx/2]=nums[heapIdx];nums[heapIdx]=temp;heapIdx = heapIdx/2;//继续向上堆化}else{//当前堆化节点在正确位置,堆化结束break;}}
}
void insertIntoHeap(vector<int>&nums,int value)
{nums.push_back(value);//先将新节点插入到最后HeapifyFromBToUp(nums,nums.size()-1);//对新节点向上堆化
}

1.3.2从上向下堆化

使用场景是将已经存在的完全二叉树,从最后一个非叶子节点开始,将该节点向下堆化,最终落到满足堆特性的位置,如下图所示。最后一个非叶子节点下标为数组长度/2,这里为7/2=3。
1.节点6小于其唯一的左孩子节点9,二者交换,节点6堆化完成。
2.节点3与其左右两个节点比较,三个节点最大是10,交换10节点和3节点,节点3堆化完成。
3.节点5与其左右两个节点比较,三个节点最大是10,交换10节点和5节点,节点5堆化完成。至此,所有节点堆化完成。

代码实现如下:nums存储的是树节点数据。

//从上向下堆化一个节点heapIdx,这里的n在排序时有用,后面讲解。void HeapifyFromUpToB(vector<int>&nums,int n,int heapIdx){int size = n;int temp=0;while(true){//找到堆化节点heapIdx和其左右孩子节点中的最大值int maxIdx = heapIdx;if(2*heapIdx<size && nums[2*heapIdx]>nums[maxIdx])maxIdx = 2*heapIdx;if(2*heapIdx+1<size && nums[2*heapIdx+1]>nums[maxIdx])maxIdx = 2*heapIdx+1;if(maxIdx==heapIdx)//堆化节点位置正确,堆化结束break;//交换堆化节点和最大值节点temp=nums[heapIdx];nums[heapIdx]=nums[maxIdx];nums[maxIdx]=temp;//heapIdx=maxIdx; //如果只是构建堆可以不用这行,但是在排序时有用,后面讲解(巧妙) }}//建堆void heapBuilder(vector<int>&nums){int size = nums.size();//for(int i=size/2;i>=1;--i)HeapifyFromUpToB(nums,size,i);//逐个堆化非叶子节点}

2.应用-查找topK

在大量数据文件中找到第K小的那个数据,可能是GB或TB级别的数据量。如果先实现排序再返回第K小的数据,占用内存空间复杂度太高O(n),如果用快排等思想,时间复杂度为O(nlogn),这种方法不合适。
我们可以维护一个大小为K的大顶堆,这个大顶堆的目的是存储前K小的数据。遍历数据文件,
1.如果新数据比栈顶小则说明当前栈顶肯定不满足前K小,将当前栈顶元素更新为新数据,并对新栈顶节点进行堆化处理。因为是对栈顶节点堆化,只能用从上向下的堆化方式
2.如果新数据不比栈顶元素小,则不做处理。
相信有了上面建堆和堆化的方法,不难实现该功能,这里不再列出源代码了。

3.应用-排序

大顶堆满足每个节点的值都不小于其孩子节点的值,栈顶节点是最大值。利用栈的这种特性我们可以很方便的完成排序工作:
1.将栈顶和最后的叶子节点交换。
2.对新的栈顶进行堆化(旧栈顶不在堆化范围),由于是栈顶堆化,所以必须使用从上向下堆化
3.重复1、2直到将最后一个新栈顶元素堆化完成结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/798547.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oliver编译安装(Windows10+VisualStudio2022)

Oliver是一个开源的非线性视频编辑器。主要基于Qt和FFmpeg开发。前置条件 电脑上需要的环境Qt(>=5.15) VisualStudio(2022,其他版也可) vcpkg软件安装安装Qt5.15令人糟糕的是,Qt如今变得不太容易安装。自从Qt5.15以后的版本,就取消了离线安装。所有的Qt后序版本就只能通过…

CVE-2021-24762 复现

CVE-2021-24762 复现一看是个wordpress,看了下版本6.0没洞,直接扔wpscan扫一下 发现了个插件一搜发现perfect-survey在1.5.2之前都有洞,直接搜exp打. 上官网找了个API重扫一遍,直接给出了CVE号!直接找个sqlmap的exp跑一下,注意第二个位置选n来设置cookie sqlmap -u "http…

Java后端对前端的数据进行校验

首先,作为一名后端程序员,大家一定要记住:不要相信前端传来的数据,后端程序员仿佛是国家的边境出入局的工作人员,承担这最后的防线,必须尽可能的防止错误信息的流入导致正确信息的流出。因此,后端程序员必须要对前端传来的数据进行校验。这里呢,发现一个很好的校验工具…

vp介绍

想要更多请到:https://budingcat.xyz 注册了解详情 可以点击工单进行沟通哦~

云计算与大数据概论--金功勋

week4的 week5 Hadoop介绍起源:Hadoop as a solution:Building blocks:Namenodeif other nodes fail:DataNode:Block 1Secondary Namenode:JobTracker:if fails:Topolosy clusterPig:Hive :PIGweek10 week13:

通过vscode 创建uniapp项目

一、创建项目 uniapp官网教程: https://uniapp.dcloud.net.cn/quickstart-cli.html控制台命令: npx degit dcloudio/uni-preset-vue#vite <projectName> npm i二、使用vscode运行项目

Java多线程复习

目录3种创建方式(现阶段推荐 Runnable接口)下载网上的图片(利用了commons-io中的copyUrlToFiles方法)小结买票的例子(Thread的构造方法,获取当前线程的名称,线程休眠)龟兔赛跑的例子实现Callable接口线程停止线程休眠线程礼让Join方法(main线程与Thread子线程)线程状…

大数据技术原理与应用——从入门到文档数据库

大数据技术原理与应用 3次信息化的浪潮研究问题的四个阶段大数据技术的层次大数据的计算模式PaaS物联网的概念云计算、大数据、物联网之间的关系Hadoop应用现状选择Hdoop需要考虑的因素Hadoop的定量评分(满分为5分)总体评价Ubuntu的一些基本知识(之所以不用CentOs,是因为其…

macOS Ventura 13.7 (22H123) 正式版发布,ISO、IPSW、PKG 下载

macOS Ventura 13.7 (22H123) 正式版发布,ISO、IPSW、PKG 下载macOS Ventura 13.7 (22H123) 正式版发布,ISO、IPSW、PKG 下载 2024 年 9 月 17 日凌晨 1 点,Tim Cook 领导的 Apple 今天发布了 macOS 15 Sequoia 正式版,iPhone 镜像、密码应用程序、窗口平铺更新等带来全新体…

C++11 线程同步接口std::condition_variable和std::future的简单使用

std::condition_variable条件变量std::condition_variable有wait和notify接口用于线程间的同步。如下图所示,Thread 2阻塞在wait接口,Thread 1通过notify接口通知Thread 2继续执行。具体参见示例代码:#include<iostream> #include<mutex> #include<thread>…

macOS Sequoia 15.0 (24A335) 正式版发布,ISO、IPSW、PKG 下载

macOS Sequoia 15.0 (24A335) 正式版发布,ISO、IPSW、PKG 下载macOS Sequoia 15.0 (24A335) 正式版发布,ISO、IPSW、PKG 下载 iPhone 镜像、Safari 浏览器重大更新、备受瞩目的游戏和 Apple Intelligence 等众多全新功能令 Mac 使用体验再升级 请访问原文链接:https://sysin…

Go runtime 调度器精讲(十一):总览全局

原创文章,欢迎转载,转载请注明出处,谢谢。0. 前言 前面用了十讲介绍了 Go runtime 调度器,这一讲结合一些图在总览下 Go runtime 调度器。 1. 状态转换图 首先是 Goroutine 的状态转换图:大部分转移路径前面几讲也介绍过,这里就不继续介绍了(下同)。 接着是 P 的状态转移…