堆的应用(堆排序、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;
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

牛客 算法题 golang语言实现

题目 HJ101 输入整型数组和排序标识&#xff0c;对其元素按照升序或降序进行排序 描述 输入整型数组和排序标识&#xff0c;对其元素按照升序或降序进行排序数据范围&#xff1a; 1 ≤ &#xfffd; ≤ 10001≤n≤1000 &#xff0c;元素大小满足 0 ≤ &#xfffd; &#…

提升企业网络安全的得力助手——EventLog Analyzer网络日志管理

在当今数字化时代&#xff0c;企业的网络安全问题变得尤为重要。为了更好地应对日益增多的威胁和安全漏洞&#xff0c;企业需要一种高效的网络日志管理工具&#xff0c;EventLog Analyzer便是其中一款卓越的解决方案。 EventLog Analyzer EventLog Analyzer是一款综合性的网络…

探索短剧市场的商机:打造短视频平台的全方位指南

目前短剧市场蓬勃发展&#xff0c;上半年备案数远超电视剧&#xff0c;彰显了短剧小程序市场潜力巨大&#xff0c;商业价值巨大。用户对短小精悍娱乐内容的需求不断增加&#xff0c;而新兴市场中有限的短剧小程序正好能够迎合这一需求。 搭建短视频平台的关键步骤&#xff1a; …

GOAT:多模态、终身学习、平台无关的机器人通用导航系统

机器人应用中涉及到的核心技术包括&#xff1a;环境感知与理解、实时定位与建图、路径规划、行为控制等。GOAT通过多模态结合终生学习的方式让你的机器人可以在未知环境中搜索和导航到任何物体。小白也可以零门槛上手。 项目地址&#xff1a;https://theophilegervet.github.i…

性能优化的一般策略及方法

性能优化的一般策略及方法 在汽车嵌入式开发领域&#xff0c;性能优化始终是一个无法回避的问题&#xff1a; 座舱 HMI 想要实现更流畅的人机交互 通信中间件在给定的 CPU 资源下&#xff0c;追求更高的吞吐量 更一般的场景&#xff1a;嵌入式设备 CPU 资源告急&#xff0c;需…

Web前端开发技术:图像与多媒体文件

在现代的Web开发中&#xff0c;图像和多媒体文件在各种网站和应用程序中扮演着至关重要的角色。它们不仅能提供更丰富的内容&#xff0c;还能大大提高应用程序的吸引力和用户体验。本文将深入介绍一些关键的Web前端开发技术&#xff0c;这些技术将有助于开发者在处理图像和多媒…

【Python3】【力扣题】367. 有效的完全平方数

【力扣题】题目描述&#xff1a; 【Python3】代码&#xff1a; 1、解题思路&#xff1a;Python函数。num的平方根 或者 num的0.5次幂。 知识点&#xff1a;float.is_integer(...)&#xff1a;判断浮点数的值是否等于整数。也可以&#xff1a;浮点数.is_integer()。 pow(a,b)&…

JAVA多线程总结

一、概念&#xff1a; 1、什么是多任务 多任务就是在同一时间做多件事情&#xff0c;如边吃饭边玩手机等。看起来是多个任务都在做&#xff0c;本质上我们的大脑在同一时间依旧只做了一件件事情 2、什么是程序 程序是指令和数据的有序集合&#xff0c;其本身没有任…

“一键转换JPG到BMP:轻松优化图片管理的革命性工具“

亲爱的用户们&#xff0c;您是否曾经因为图片格式不兼容而感到烦恼&#xff1f;是否曾经为了转换图片格式而耗费大量时间&#xff1f;现在&#xff0c;我们为您带来了一款全新的图片转换工具&#xff0c;它可以轻松解决您的问题&#xff01; 首先&#xff0c;我们进入首助编辑高…

同旺科技 USB 转 RS-485 适配器 -- 隔离型

内附链接 1、USB 转 RS-485 适配器 隔离版主要特性有&#xff1a; ● 支持USB 2.0/3.0接口&#xff0c;并兼容USB 1.1接口&#xff1b; ● 支持USB总线供电&#xff1b; ● 支持Windows系统驱动&#xff0c;包含WIN10 / WIN11 系统32 / 64位&#xff1b; ● 支持Windows …

idea打开.class文件没有反编译

1 问题描述 新安装的idea开发工具&#xff0c;打开.class文件查看内容时发现没有将文件进行反编译&#xff0c;所以具体的代码实现看不到。如图所示&#xff1a; 尝试了各种办法解决&#xff0c;最终都没有解决我的问题&#xff0c;其他同事的idea开发工具都可以打开.class文件…

基于SpringBoot与Vue的增城高校二手物品交易系统

基于SpringBoot 与 Vue 的增城高校二手物品交易系统的设计与实现 摘要&#xff1a;随着生活水平和在校大学生消费能力的提高&#xff0c;学生用品的迭代速度越来越快&#xff0c;导致大量的闲置物品无法及时完成处理&#xff0c;而传统的线下摆摊等方式处理不仅效率低&#xf…

Java-认识异常

本章重点&#xff1a; 1. 异常概念与体系结构 2. 异常的处理方式 3. 异常的处理流程 4. 自定义异常类 1. 异常的概念与体系结构 1.1 异常的概念 在Java中&#xff0c;将程序执行过程中发生的不正常行为称为异常。比如之前写代码时经常遇到的&#xff1a; 1. 算术异常 2. 数组…

详解STL库—map和set

目录 一、关联式容器 二、键值对 SGI-STL中关于键值对的定义&#xff1a; 三、set 3.1 set的介绍 3.2 set的使用 1.set的模板参数列表​编辑 2. set的构造 3. set的迭代器 4. set的容量 5. set修改操作 6. set的使用举例 四、map 4.1map的介绍 4.2 map的使用 1…

揭秘!9个月完成亚运会的整体数字化观测

项目背景与业务场景 2023 第 19 届亚运会在杭州举办&#xff0c;这将提高杭州的国际知名度&#xff0c;促进杭州经济、社会的全面发展&#xff0c;并将进一步推动奥林匹克运动在中国的发展&#xff0c;并且提升杭州城市形象和国际影响力。为亚运村村民提供便捷周到的服务和丰富…

【NI-RIO入门】为CompactRIO供电

在大多数情况下&#xff0c;您可以使用可直接连接系统的电源&#xff0c;例如墙上的电源插座。但是&#xff0c;某些应用程序或环境缺乏可用电源&#xff0c;您必须使用其他电源&#xff0c;例如电池。无论您是否有可用电源&#xff0c;您可能都希望通过为系统提供一些冗余来确…

京东秒杀之商品展示

1 在gitee上添加.yml文件 1.1 添加good-server.yml文件 server:port: 8084 spring:datasource:url: jdbc:mysql://localhost:3306/shop_goods?serverTimezoneGMT%2B8driverClassName: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceusername: rootpa…

自动驾驶HWP功能规范

HWP功能规范 Highway Pilot Functional Specification 文件状态&#xff1a; 【√】草稿 【】正式发布 【】正在修改 文件起草分工 撰写&#xff1a; 审核&#xff1a; 编制&#xff1a; 签名&#xff1a; 日期&#xff1a; 审核&#xff1a; 签名&#xff1a; 日期&am…

抖音视频如何无水印下载,怎么批量保存主页所有视频没水印?

现在最火的短视频平台莫过于抖音&#xff0c;当我们刷到一个视频想下载下来怎么办&#xff1f;我们知道可以通过保存到相册的方式下载&#xff0c;但用这种方法下载的视频带有水印&#xff0c;而且有些视频不能保存到相册&#xff08;这是视频作者设置了禁止下载&#xff09;。…

c# 简单web api接口实例源码分析

CreateHostBuilder(args).Build().Run();这句语句处于c#webapi程序的第一句&#xff0c;它的作用是&#xff1a;启动接口的三个步骤&#xff1a; 创建一个HostBuilder对象。执行IHostBuilder.Build()方法创建IHost对象。执行IHost.Run()方法启动。 创建和配置Host&#xff08;…