【数据结构】堆排序与TOP-K问题

news2024/9/23 9:30:17

🌈个人主页:Yui_
🌈Linux专栏:Linux
🌈C语言笔记专栏:C语言笔记
🌈数据结构专栏:数据结构

文章目录

  • 1.堆排序
    • 1.1 建堆
    • 1.2 利用堆删除思想来进行排序
    • 1.3 堆排序的时间复杂度
  • 2.TOP-K问题

1.堆排序

堆排序就是利用堆的思想进行排序,总共分为两个步骤:

1.1 建堆

  • 升序:建大堆
  • 降序:建小堆
    利用向下调整建堆
    提问:为什么向下调整可以建堆
    回答:
    向下调整的关键就除了要调节的地方不对,其下方都为正确的堆。
    以下图为例:以10为根的左右子树,都满足小堆(堆)的性质,只有根节点不满足时,因此只需将根节点往下调,整合到合适的位置就可以了。
    向下调整

为了我只有由后往前向下调整就可以了,第一次要传的参数就是最后一个节点的父节点。然后依次传入前面是位置就可以了。

#include <stdio.h>

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

//建大堆
void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child = child + 1;
		}
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

int main()
{
	int arr[] = { 2,3,5,7,4,6,8,65,100,70,32,50,60 };//初始化一个小堆
	int n = sizeof(arr) / sizeof(arr[0]);
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(arr, n, i);//通过向下调整建立大堆
	}
	for (int i = 0; i < n; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}
//打印结果:
/*
100 70 60 65 32 50 8 3 7 4 2 5 6
*/

1.2 利用堆删除思想来进行排序

建堆和堆删除中都用到了向下调整,因此掌握了向下调整就可以完成堆排序。
提问:为什么升序需要建大堆呢?
回答:堆排序的本质是选择排序,每次都要选择一个最大的数到数组的最后一位,那么问题就变成了如何选择最大的数到数组最后一位,要找出堆中最大数就必须要用到大堆,因为大堆中最大的数就在堆堆顶,通过一次次的选择就可以将数组排序。
下面是画图解释:
利用堆删除思想来进行排序

#include <stdio.h>

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

//建大堆
void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child = child + 1;
		}
		if (a[child] > a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

int main()
{
	int arr[] = { 2,3,5,7,4,6,8,65,100,70,32,50,60 };
	int n = sizeof(arr) / sizeof(arr[0]);
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(arr, n, i);
	}
	//排序
	for (int end = n - 1; end >= 0; --end)
	{
		swap(&arr[0], &arr[end]);
		AdjustDown(arr, end, 0);
	}
	for (int i = 0; i < n; ++i)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}
//打印结果:
/*
2 3 4 5 6 7 8 32 50 60 65 70 100
*/

1.3 堆排序的时间复杂度

O(N*logN)

2.TOP-K问题

TOP-K问题:即求数据结合中前k个最大元素或者最小元素,一般情况下数据量都比较大。
比如:专业前10名,时间500强、游戏中的前100的玩家。
对于TOP-K问题,能想到的最简单的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:

  1. 用数据集合前K个元素来建堆
  • 前k个最大的元素,则建小堆
  • 前k个最小的元素,则建大堆
  1. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素
    将剩余N-K个元素依次与堆顶元素比完后,堆中剩余的K个元素就是所求得前K个最小或者最大的元素。

下面我们将找出1000000个数中最大的10个数,为此我们需要建造一个大小为10的小堆。
主要步骤:

  1. 创建1000000个随机数,数值范围[0,999999]
  2. 创建一个大小为10的小堆
  3. 开始进堆,如果当前数值大于堆顶数据,就将堆顶数值替换为当前数值,然后向下调整,让大的数下沉。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

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

//建小堆
void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			child = child + 1;
		}
		if (a[child] < a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

int main()
{
	int n = 10000;
	int* a = (int*)malloc(sizeof(int) * n);
	srand((unsigned int)time(NULL));//生成随机种子
	for (int i = 0; i < n; ++i)
	{
		a[i] = rand() % 1000000;//数据范围:[0,999999]
	}
	//选出数据中最大的10个数,建小堆
	//为了证明确实可以找到,我们需要自己设置10个大于范围的数,如果最后被找到就说明正确
	a[5] = 1000000 + 1;
	a[55] = 1000000 + 2;
	a[99] = 1000000 + 3;
	a[1001] = 1000000 + 4;
	a[123] = 1000000 + 5;
	a[124] = 1000000 + 6;
	a[18] = 1000000 + 7;
	a[1111] = 1000000 + 8;
	a[999] = 1000000 + 9;
	a[100] = 1000000 + 10;
	int heap[10] = { 0 };
	for (int i = 0; i < n; ++i)
	{
		if (a[i] > heap[0])
		{
			heap[0] = a[i];
			AdjustDown(heap, 10, 0);
		}
	}
	for (int i = 0; i < 10; ++i)
	{
		printf("%d ", heap[i]);
	}
	return 0;
}
//打印结果:
/*
1000001 1000002 1000003 1000004 1000009 1000006 1000005 1000007 1000008 1000010
*/

最后的结果确实是我能自己修改的数,说明查找成功。

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

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

相关文章

Uniapp之微信小程序计算器

UI仿的iOS手机计算器&#xff0c;基本功能已经实现&#xff0c;如下效果图 具体使用可以参考微信小程序&#xff1a;日常记一记--我的---计算器 第一步&#xff1a;UI界面设计 1&#xff0c;strClass模块是计算过程代码展示 2&#xff0c;result-view模块是结果展示 3&#xff…

嵌入式学习---DAY24:进程--二

一、exec函数族----启动一个新程序 用fork创建子进程后执行的是和父进程相同的程序&#xff08;但有可能执行不同的代码分支&#xff09;&#xff0c; 子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时&#xff0c;该进程的 用户空间代码和数据完全被…

SHT30温湿度传感器全解析——概况,性能,MCU连接,样例代码

常见温湿度传感器测量范围&#xff1a;(价格仅供参考&#xff0c;具体性能要看折线图) 型号DHT11DHT20AHT10AHT20AHT30SHT20价格&#xffe5; 2.49&#xffe5;3.04&#xffe5; 1.9&#xffe5;1.4&#xffe5; 1.3&#xffe5;5.5温度测量范围20—90%RH0—100%RH0—100%RH0—…

pycharm最新专业版激活码

pycharm最新专业版激活码 Pycharm下载地址&#xff1a;pycharm下载 首先&#xff0c;我们打开下载的 pycharm 专业版并安装。 按照下图所示先点击上方的 Activation code&#xff0c;再将激活码粘贴至输入框&#xff0c;最后点击 Activate 激活。 激活码&#xff1a; OS2AN…

旋转关系介绍

目录 旋转矩阵与轴角 旋转矩阵与欧拉角 旋转矩阵与四元数 轴角与四元数 轴角与欧拉角 欧拉角与四元数 欧拉角与四元数 旋转矩阵与轴角 设旋转矩阵R[■8(r_11&r_12&r_13r_21&r_22&r_23r_31&r_32&r_33)]&#xff0c;轴角使用一个单位向量n和一个角…

Go--GMP调度模型

目录 GMP模型G、M、P简介P和M的个数**P和M何时会被创建**goroutine创建流程goroutine什么时候会被挂起 GMP的调度调度流程调度策略调度时机同时启动了一万个goroutine&#xff0c;会如何调度&#xff1f; GMP模型 G、M、P简介 GMP是Go运行时调度层面的实现&#xff0c;包含4个…

质量对中国开发商提升游戏品牌信誉和信任度的影响

随着全球游戏产业的持续增长&#xff0c;中国开发商正在大举进军国际市场。然而&#xff0c;他们面临的关键挑战之一是建立和维护与全球参与者的品牌信誉和信任。他们的游戏质量在实现这一目标方面起着至关重要的作用。从技术性能到故事讲述和本地化&#xff0c;高质量的游戏对…

OpenGL3.3_C++_Windows(35)

PBR_IBL漫反射 IBL图像的光照(Image based lighting&#xff09;&#xff1a;非直接光源&#xff0c;它是一种更精确的环境光照输入格式&#xff0c;甚至也可以说是一种全局光照的粗略近似。环境光照&#xff1a;获取每个wi光源辐射率&#xff0c;求辐照度&#xff1a;将周围环…

Linux学习笔记11(计算机网络)

目录 网络七层模型/五层模型 IP地址分类 CIDR Centos7的网卡IP配置 RockyLinux9的网卡IP配置 网络七层模型/五层模型 自下到上 物理层&#xff1a; 建立物理连接&#xff0c;传输 0 和 1 的比特流 数据链路层&#xff1a; 物理地址寻址&#xff0c;流量控制&#xff0c;差错…

基于vue框架的SSM基于B_S的毕业设计题目管理系统的设计与实现ij0q7(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;学生,教师,毕设题目,毕设选题,毕设任务书,开题报告,中期检查,毕业论文,论文成绩,答辩成绩,答辩通知,班级 开题报告内容 基于Vue框架的SSM&#xff08;SpringSpring MVCMyBatis&#xff09;的毕业设计题目管理系统设计与实现 开题报告…

刷题记录第109天-K个一组反转链表

解题思路&#xff1a; 第一步&#xff1a;实现一个数组&#xff0c;给定一段链表的头结点和尾节点&#xff0c;反转该链表&#xff0c;并返回新的头结点和尾结点。 第二步&#xff1a;初始化一个虚拟头结点&#xff0c;用于记录最终头结点和规范操作。 第三步&#xff1a;给定一…

​产品经理-​你如何理解“互联网思维(35)

在产品规划和功能改版中&#xff0c;确实非常重视用户需求和体验。产品需求是互联网产品的核心 用户体验是互联网产品的重点。在互联网新产品规划中&#xff0c;会非常重视用户验证环节 确保做出来的东西确实是用户想要的&#xff1b;而在已经上线的产品中&#xff0c;往往会有…

Raspberry Pi Pico 家族的进化 —— RP2040、RP2350与RP2354性能比较

随着树莓派Pico系列的不断扩展&#xff0c;其背后的芯片也得到了升级和改进。从最初的RP2040到最新的RP2354&#xff0c;每一次迭代都带来了新的功能和性能提升。本文将详细对比RP2040、RP2350和RP2354三款芯片的关键特性&#xff0c;帮助开发者了解它们的差异&#xff0c;并选…

Windows File Recovery卡在99%怎么解决?实用指南!

为什么会出现“Windows File Recovery卡在99%”的问题&#xff1f; Windows File Recovery&#xff08;Windows文件恢复&#xff09;是微软设计的命令行应用程序。它可以帮助用户从健康/损坏/格式化的存储设备中恢复已删除/丢失的文件。 通过输入相关命令&#xff0c;设置源/…

【轨物推荐】技术创新的演进逻辑

注&#xff1a;本文节选自郭朝晖老师的《知行-工业基因的数字化演进》 推进数字化技术的过程本质上是一种技术创新。理解创新的逻辑&#xff0c;有利于推进数字化技术。 科技工作的价值往往短期被高估&#xff0c;长期被低估。短期被高估&#xff0c;是因为忽视了技术应用过程…

LSPosed模块开发第一篇

安装LSPosed 设备pixel 3a Android 12 Magisk root 环境 LSPosed地址&#xff1a; https://github.com/LSPosed/LSPosed 下载zygisk的&#xff0c;riru没效果 https://github.com/LSPosed/LSPosed/releases 下载完push 到手机&#xff0c;Magisk 安装模块 Magisk设置里面的Z…

【人工智能】【机器学习】- 好书推荐之《深度学习调参指南》

目录 目标读者 核心内容 特色 结构 《深度学习调参指南》是一份由Google和哈佛大学的研究人员与工程师共同编写的实战手册&#xff0c;旨在帮助读者系统性地优化深度学习模型的性能。该指南强调了在深度学习实践中遇到的实际问题和解决方案&#xff0c;尤其关注超参数调优的…

go-zero结合自定义模版校验前端参数

一、自定义模版的使用 如果想对官网goctl命名生成的项目结构改变的话,可以使用模版&#xff0c;自定义模版,然后生成自己想要的文件 1、使用命令将官方模版映射到本地 goctl template init2、在项目的根目录下添加文件夹,把刚刚映射到本地的拷贝到项目中 3、使用模版根据api文…

luckyexcel 编辑预览excel文件

luckyexcel 编辑预览excel文件 支持后端传文件流预览编辑&#xff0c;也支持选择本地文件编辑预览 看效果 上代码 <template><div style"margin: 30px"><div class"button-box2"><div><div style"color: red">…

【精通SDL之----SDL_RenderReadPixels截屏】

SDL_RenderReadPixels截屏 前言一、SDL_RenderReadPixels简介二、问题现象三、规避方案1. 离屏纹理2. ding! *灵光一现* 前言 最近使用SDL2在鸿蒙系统(Harmoney OS)上截取视频播放过程中的数据&#xff0c;发现捕获的数据为空&#xff0c;然在windows上却可以正常捕获&#xff…