堆的应用(堆排序、Top-K问题)

文章目录

  • 1 堆排序
  • 2 Top-K问题

1 堆排序

堆排序是一种基于二叉堆(通常使用数组实现)的排序算法。
它的基本思想是利用堆这种数据结构的性质,通过建立一个堆(大堆或小堆),使得堆的根节点是所有节点中的最大值(大堆)或最小值(小堆)。然后,将根节点与堆的最后一个节点交换,使得最大值或最小值进入有序区。接着,对剩余的未排序部分重新调整成堆,重复这个过程,直到整个数组有序。

建堆和堆调整堆中都用到了向下调整,因此掌握了向下调整法,就可以完成堆排序。对该算法不清楚的,可以参考这篇文章,里面进行了详细的介绍:堆详解(C语言实现)
堆排序步骤:

  1. 构建初始堆(建堆): 从最后一个非叶子节点开始,对每个节点进行向下调整(调整成堆的性质,大堆或小堆)。
    排升序:建大堆,原因如下:
    在堆排序中,升序排序要建立大堆的主要原因是为了保证每次选择堆顶元素都是堆中的最大值
    在排升序时,每次选择堆顶元素与堆的最后一个元素交换,由于堆顶是最大值,将其与末尾元素交换后,最大值就被移到了数组的末尾,而在交换后,需要重新调整堆,使剩余部分重新构成大堆,这样,下一次选择堆顶元素时,依然得到的是剩余元素中的最大值。通过这个过程,每次都能选择到当前堆中的最大值,将其移到数组末尾,逐步形成有序部分,从而实现升序排序。
    排降序:建小堆,原因如下:
    在堆排序中,降序排序要建立小堆的主要原因是为了保证每次选择堆顶元素都是堆中的最小值
    在排降序时,每次选择堆顶元素与堆的最后一个元素交换,由于堆顶是最小值,将其与末尾元素交换后,最小值就被移到了数组的末尾,而在交换后,需要重新调整堆,使剩余部分重新构成小堆,这样,下一次选择堆顶元素时,依然得到的是剩余元素中的最小值。通过这个过程,每次都能选择到当前堆中的最小值,将其移到数组末尾,逐步形成有序部分,从而实现降序排序。
  2. 排序: 交换堆的根节点(最大值或最小值)与堆的最后一个节点,并对剩余部分重新调整成堆。
    重复: 重复步骤2,直到整个数组有序。

例如利用堆排序对该数组{ 8, 5, 3, 9, 1}进行排降序,过程如下:

  1. 建小堆
    在这里插入图片描述
  2. 排序
    在这里插入图片描述

代码如下:

void AdjustDown(int* nums, int n, int parent)
{// 左孩子的索引int child = parent * 2 + 1;// 循环直到没有左孩子while (child < n){// 如果右孩子存在且比左孩子小,选择右孩子//若实现大根堆,这里nums[child + 1] < nums[child]的 < 换成 >if (child + 1 < n && nums[child + 1] < nums[child]){++child;}// 如果孩子比父亲小,交换它们的值//若实现大根堆,这里nums[child] < nums[parent]的 < 换成 >if (nums[child] < nums[parent]){// 孩子比父亲大,堆的有序性已经恢复,退出循环int tmp = nums[child];nums[child] = nums[parent];nums[parent] = tmp;}else{break;}// 更新父亲和孩子的索引parent = child;child = parent * 2 + 1;}
}void HeapSort(int* nums, int n)
{//建堆//升序,建大堆//降序,建小堆for (int i = (n - 2) / 2; i >= 0; --i){AdjustDown(nums, n, i);//非叶子节点开始向下调整}int end = n - 1;while (end > 0){//交换堆的根节点与堆的最后一个节点int tmp = nums[end];nums[end] = nums[0];nums[0] = tmp;//并对剩余部分重新调整成堆。AdjustDown(nums, end, 0);end--;}
}

总之,堆排序是一种选择排序,它利用了堆的性质:堆顶的数据,是堆中最大的数据(或者最小的数据)。该算法通过不断选择堆顶元素,将其与堆的最后一个元素交换,然后调整堆,使剩余部分重新构成堆,重复这个过程直到整个数组有序。

2 Top-K问题

Top-K 问题是在一个包含大量数据的集合中,找出前 K 个最大或最小的元素数据的问题。通常数据量都是比较大的。

  1. 关于解决TOP-K问题,我们首先想到的是对这个数据集合拍升序或者降序,然后取前 K 个数据,就能解决这个问题。该方法的缺点是不适用于数据量极大的情况。这是因为,利用排序算法,需要将数据加载到内存中,在内存中进行排序,然而当数据量大到无法一次性加载到内存中时,排序算法的效率就会受到限制。
  2. 因此,就有人提出了使用堆来解决这个问题。该算法的思想是:用数据集的前k个数据,建一个大小为 K 的小顶堆(Top K 最大问题)或大顶堆(Top K 最小问题)。依次遍历剩余n - k个元素,将元素与堆顶比较,若大于(或者小于)堆顶,则替换堆顶,并进行堆调整。这样,最终堆中的元素就是前 K 个最大或最小的元素。

例如:面试题 17.14. 最小K个数
过程如下:

  1. 用数据集的前k个数据,建一个大小为 K 的小根堆。
  2. 依次遍历剩余n - k个元素,将元素与堆顶比较,若大于堆顶,则替换堆顶,并进行堆调整。

代码如下:

 //向下调整算法void AdjustDown(int* nums, int n, int parent){int child = parent * 2 + 1;while (child < n){if (child + 1 < n && nums[child + 1] > nums[child]){++child;}if (nums[child] > nums[parent]){int tmp = nums[child];nums[child] = nums[parent];nums[parent] = tmp;}else{break;}parent = child;child = parent * 2 + 1;}}
int* smallestK(int* arr, int arrSize, int k, int* returnSize)
{int* nums = (int*)malloc(sizeof(int) * k);for (int i = 0; i < k; ++i){nums[i] = arr[i];}//前k个数建大堆for (int i = (k - 2) / 2; i >=0; --i){AdjustDown(nums, k, i);}//依次遍历剩余n - k个元素for (int i = k; i < arrSize; ++i){//将元素与堆顶比较,若大于堆顶,则替换堆顶if (k > 0 && arr[i] < nums[0]){nums[0] = arr[i];//进行堆调整AdjustDown(nums, k, 0);}}*returnSize = k;return nums;
}

至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。
创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!
如果本篇博客有任何错误,请批评指教,不胜感激 !!!
在这里插入图片描述

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

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

相关文章

在线 SQL 模拟器SQL Fiddle使用简介

在线 SQL 模拟器SQL Fiddle使用简介 有时候&#xff0c;我们想去验证 SQL语句&#xff0c;却缺少数据库环境&#xff0c;那该怎么办呢&#xff1f; 这时候在线 SQL 模拟器就有了用武之地。SQL 模拟器免安装&#xff0c;可以在网页直接运行 SQL 。 SQL Fiddle 支持 MySQL、Orac…

SystemVerilog 入门

文章目录 包定义SystemVerilog 数据类型结构体 SystemVerilog 过程块可嵌套模块接口 System Verilog 的优点 提高了硬件建模能力、编码效率和抽象能力&#xff1b;RTL 级、系统级行为描述&#xff1b; 增强了验证能力和为大规模复杂设计编写有效、无竞争测试程序的断言功能&am…

spring-framework-5.2.25.RELEASE源码环境搭建

环境准备 spring-framework-5.2.25.RELEASEIntelliJ IDEA 2022.3.1java version “11.0.20” 2023-07-18 LTSGradle 5.6.4java version “1.8.0_301” 下载spring-framework-5.2.25.RELEASE源码 git clone https://gitee.com/QQ952051088/spring.git cd spring gradlew buil…

[学习记录]Node event loop 总结流程图

文章目录 文章来源根据内容输出的流程图待处理遗留的问题参考 文章来源 详解JavaScript中的Event Loop&#xff08;事件循环&#xff09;机制 根据内容输出的流程图 待处理 这里从polling阶段开始 好像有些问题 遗留的问题 为什么“在I/O事件的回调中&#xff0c;setImmediate…

深度学习:全面了解深度学习-从理论到实践

深度学习&#xff1a;全面了解深度学习-从理论到实践 摘要&#xff1a;本文旨在为读者提供一份全面的深度学习指南&#xff0c;从基本概念到实际应用&#xff0c;从理论数学到实践技术&#xff0c;带领读者逐步深入了解这一领域。我们将一起探讨深度学习的历史、发展现状&#…

使用Tensorboard可视化 遇到无法访问此网站

问题&#xff1a; 使用Tensorboard可视化 遇到无法访问此网站 解决方法&#xff1a;后面加上服务器ip[参考] tensorboard --logdir目标目录 --hostxxx.xxx.xxx.xx

leetcode LCR24反转单链表

反转单链表 题目描述 题目分析 先来说迭代的思想&#xff1a; 上面next cur->next应该放在cur->next pre前面执行&#xff0c;这里笔误 再来说递归的思想&#xff1a; 题目代码 这个代码里面我加了我自己写的测试数据&#xff0c;自己可以去找对应的部分&#xff0c…

【功能测试】软件系统测试报告

1.引言 1.1.目的 本测试报告为 xxx 系统测试报告&#xff0c;本报告目的在于总结测试阶段的测试及测试结果分析&#xff0c;描述系统是否达到需求的目的。 本报告预期参考人员包括测试人员、测试部门经理、开发人员、项目管理人员等。 1.2.参考文档 《xxxx系统需求规格说明…

Java线程安全问题

什么是线程安全问题 用程序模拟线程安全问题 主线程 package com.itheima.d3;public class ThreadTest {public static void main(String[] args) {//1、创建一个账户对象&#xff0c;代表两个人的共享账户Accout acc new Accout("ICBC-110",100000);//2、创建两个…

Django回顾【二】

目录 一、Web框架 二、WSGI协议 三、 Django框架 1、MVC与MTV模型 2、Django的下载与使用 补充 3、启动django项目 补充 5、 Django请求生命周期 四、路由控制 1、路由是什么&#xff1f; 2、如何使用 3、path详细使用 4、re_path详细使用 5、反向解析 6、路由…

Linux 中的 ls 命令使用教程

目录 前言 如何运用 ls 命令 1、列出带有所有权的文件和目录 2、获取以人类可读的方式显示的信息 3、列出隐藏文件 4、递归列出文件 5、在使用 ls 时对文件和目录做区分 6、列出指定扩展名的文件 7、基于大小对输出内容排序 8、根据日期和时间排序文件 让我们来总结…

从零带你底层实现unordered_map (2)

&#x1f4af; 博客内容&#xff1a;从零带你实现unordered_map &#x1f600; 作  者&#xff1a;陈大大陈 &#x1f680; 个人简介&#xff1a;一个正在努力学技术的准C后端工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎私信&#xff01; &#x1f496; 欢迎大家…

figma 基础使用 —— 常用方法

一、 导入组件 分成两种方式 &#xff08;1&#xff09;离线的包导入&#xff08;iOS 常用组件.fig 直接拖拽到figma最近网页&#xff09; &#xff08;2&#xff09;在插件市场下载https://www.figma.com/community 二、figma中使用标尺 快捷键&#xff1a;shift R 三、插…

宿主Linux——KVM安装Windows7系统

KVM虚拟技术 KVM(Kernel-based Virtual Machine) 是基于Linux内核的开源虚拟化技术&#xff0c;在一台物理机上可同时运行多个虚拟系统。KVM使用硬件虚拟化扩展&#xff0c;例如Intel的VT和AMD的AMD-V&#xff0c;在性能方面更加高效&#xff0c;可提供更好的计算能力和响应速…

【从浅识到熟知Linux】基本指令之rmdir和rm

&#x1f388;归属专栏&#xff1a;从浅学到熟知Linux &#x1f697;个人主页&#xff1a;Jammingpro &#x1f41f;每日一句&#xff1a;加油努力&#xff0c;这次写完真的真的真的要去干饭了&#xff01; 文章前言&#xff1a;本文介绍rmdir和rm指令用法并给出示例和截图。 文…

存在即合理,低代码的探索之路

目录 一、前言 二、低代码迅速流行的原因 三、稳定性和生产率的最佳实践 四、程序员用低代码开发应用有哪些益处&#xff1f; 1、提升开发价值 2、利于团队升级 一、前言 低代码的热潮至今未消停&#xff0c;从阿里钉钉跨平台协作方式&#xff0c;再到飞书上的审批流程&#xf…

房屋租赁出售经纪人入驻小程序平台

一款专为房屋中介开发的小程序平台&#xff0c;支持独立部署&#xff0c;源码交付&#xff0c;数据安全无忧。 核心功能&#xff1a;房屋出租、经纪人独立后台、分佣后台、楼盘展示、房型展示、在线咨询、地址位置配套设施展示。 程序已被很多房屋交易中介体验使用过&#x…

uni-app 离线打包安卓Apk(小白上手)

场景&#xff1a; 在使用uni-app 开发apk时&#xff0c;使用云打包有次数限制。尤其对于测试阶段是无比难受的&#xff0c;通常是浪费打包次数进行打包或者通过usb 给测试机更新开发环境&#xff0c;但这都是无比漫长的过程 尤其有多个测试机真的是噩梦般的存在 下载离线打包示…

【数据库】聊聊一颗B+树 可以存储多少数据

我们知道数据库使用的数据结构是B树&#xff0c;但是B树可以存储多少数据呢&#xff0c;在面试中也是经常会问的问题&#xff0c;所以我们从根上理解这个问题。 操作系统层面 数据都是存储在磁盘中的&#xff0c;而磁盘中的数据都是以最新单位扇区进行分割。一个扇区的大小是…