【数据结构】 堆排序与TopK问题详解

news2025/5/31 18:34:55

在学习完堆的创建后,就轮到了标题的两个问题
这两个问题在实际生活中会有比较强的实际问题解决能力
先分别解释一下

  • 堆排序:
    运用堆的思想进行排序,时间复杂度为O(NlogN)
  • TopK:
    从一大堆数据中选择K个最大或最小的数据,我们简称tTopK

堆的创建,关于堆的详情请点击。

目录

  • 堆排序:
    • 思想:
    • 代码实现:
    • 源代码:
  • TopK:
  • 思想:
    • 代码实现:
    • 源代码:

堆排序:

思想:

假设我们有一个小堆为N个数,先在要对其排序,那么这个小堆适合什么排序呢?

答案是降序

绝大部分同学可能都会认为是升序,
因为最上边的元素是最小的,我们将第一个固定住,在对其后边N-1个再次进行建堆,就可以完美得到一个升序的数组,
注意:

但是我们忽略了建堆的时间复杂度为O(lNogN),对N个数进行建堆,比冒泡排序有过之而无不及,所以我们不会去用这样一个华而不实的方法

所以我们小堆其实更适合降序,将建堆之后的第一个元素与数组末尾进行交换,再对这N-1个数进行向下调整算法,每调整一次时间复杂度为O(N),以此类推,再将第一个与倒数第二个交换…

代码实现:

我们既然进行排序,就要有一个待排序的数组,我们将数组传给堆排序,同样,当然也需要知道数组个数

	int arr[] = { 5,7,3,9,1,2,6,0 };
	HeapSort(arr, sizeof(arr) / sizeof(arr[0]));

然后我们就可以对这个数组进行建堆了,你的升降序也是根据你建的堆来进行的,要仔细区分
对于建堆,我们有两种方法

自上而下建堆:
这也是我们最容易想到的一种
利用循环将数组变成小堆

	for (int child = 0; child < size; child++)
	{
		AdjustUp(arr, child);
	}

自下而上建堆:
这是我们推荐的一种,因为他的时间复杂度小于上一种方式(从最后一个叶子节点的父节点开始,少了最后一层,而最后一层接近N/2个节点),同时,他只会用到向下调整算法,在进行排序时也只会用到向下算法,故很适合我们使用

	int parent = (size - 1 - 1) / 2;
	while (parent)
	{
		AdjustDown(arr, size, parent);
		parent--;
	}
	AdjustDown(arr, size, parent);

排序代码:

	//因为是小堆,排序降序
	int child = size - 1;
	for (int i = child; i > 0; i--)
	{
		Swap(&arr[0], &arr[i]);
		AdjustDown(arr, i, 0);
	}
	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}

源代码:

heap.cheap.h我们用到的依然是开头链接处的代码,这里我们直接引用他们

void HeapSort(int* arr, int size)
{
	//建堆:向下与向上
	
	向下
	//for (int child = 0; child < size; child++)
	//{
	//	AdjustUp(arr, child);
	//}
	
	//向上
	int parent = (size - 1 - 1) / 2;
	while (parent)
	{
		AdjustDown(arr, size, parent);
		parent--;
	}
	AdjustDown(arr, size, parent);
	
	//因为是小堆,排序降序
	int child = size - 1;
	for (int i = child; i > 0; i--)
	{
		Swap(&arr[0], &arr[i]);
		AdjustDown(arr, i, 0);
	}
	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}
}


int main()
{
	int arr[] = { 5,7,3,9,1,2,6,0 };
	HeapSort(arr, sizeof(arr) / sizeof(arr[0]));

	return 0;
}

TopK:

思想:

关于TopK我们有两种实现方法:

  1. N个数据进行建堆,在依次Pop掉堆顶,得到K个最大或最小的数据,但这种方式显然代价太大,且如果N太大,malloc会开辟不出来这么多数据的数组
  2. 我们先建一个K个数的堆,假设为小堆,那么此时还是问同学们一个问题,小堆适合选出最大的还是最小的呢?
    解:
    答案是最大的,
    因为我们在建好一个小堆后,需要拿堆顶的元素与N个数据中剩下的元素比较,又因为我们是小堆,所以当一个元素大于栈顶元素时,那个元素就会进入堆,我们进行向下排序,那个元素就会下沉,直到选出K个最大的数据,
    如果建立大堆的话,假设堆顶是K个数中最大的数据,就会挡在前边,另外几个次大的数据就会入不了堆,造成错误

代码实现:

首先创建一个文件,里面有很多的数据

void CreatData()
{
	FILE* fin = fopen("pata.txt", "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}

	//write data
	srand(time(NULL));
	for (int i = 0; i < 10000000; i++)
	{
		int x = (rand() + i) % 10000000;
		fprintf(fin, "%d\n", x);
	}

	fclose(fin);
}

注意:
创建完文件后我们要进入文件,改变几个数值(改变为超过取模的数字,这样我们就可以验证我们的代码准确性在这里插入图片描述
创建一个大小为K的堆

FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}

	// 建一个k个数小堆
	int* minheap = (int*)malloc(sizeof(int) * k);
	if (minheap == NULL)
	{
		perror("malloc error");
		return;
	}

将大数据中的前N个放入堆中

	// 读取前k个,建小堆
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minheap[i]);
		AdjustUp(minheap, i);
	}

依次读取,直到读取完毕并打印数据

	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		if (x > minheap[0])
		{
			minheap[0] = x;
			AdjustDown(minheap, k, 0);
		}
	}

	for (int i = 0; i < k; i++)
	{
		printf("%d ", minheap[i]);
	}
	printf("\n");

	free(minheap);
	fclose(fout);

源代码:

void CreatData()
{
	FILE* fin = fopen("pata.txt", "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}

	//write data
	srand(time(NULL));
	for (int i = 0; i < 10000000; i++)
	{
		int x = (rand() + i) % 10000000;
		fprintf(fin, "%d\n", x);
	}

	fclose(fin);
}

void TopK(char* filename, int k)
{
	FILE* fout = fopen(filename, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		return;
	}

	// 建一个k个数小堆
	int* minheap = (int*)malloc(sizeof(int) * k);
	if (minheap == NULL)
	{
		perror("malloc error");
		return;
	}

	// 读取前k个,建小堆
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minheap[i]);
		AdjustUp(minheap, i);
	}

	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		if (x > minheap[0])
		{
			minheap[0] = x;
			AdjustDown(minheap, k, 0);
		}
	}

	for (int i = 0; i < k; i++)
	{
		printf("%d ", minheap[i]);
	}
	printf("\n");

	free(minheap);
	fclose(fout);
}

int main()
{
//粘贴时注意先将创建数据的函数放出来,单独修改后再TopK
	//CreatData();
	TopK("data.txt", 5);
	return 0;
}

有问题及时询问博主,25小时高强度冲浪

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

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

相关文章

oj赛氪练习题

数组调整 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();int k scanner.nextInt();int[] arr new int[n];for (int i 0; i < n; i) {arr[i] scanner.nextIn…

充电桩自检流程

1、常规自检流程介绍 充电桩自检流程通常包括以下几个方面&#xff1a; 外观检查&#xff1a;检查充电桩外观是否完好&#xff0c;无损坏、严重污染等问题。连接检查&#xff1a;检查充电桩与电源的连接是否牢固&#xff0c;线缆是否完整无损。安全性检查&#xff1a;检查充电…

750mA Linear Charger with Power Path Management

一、General Description YHM2711 is a highly integrated, single-cell Li-ion battery charger with system power path management for space-limited portable applications. The full charger function features Trickle-charge, constant current fast charge and const…

Upsert 及冲突(GORM)

GORM支持了数据库的upsert操作 upsert操作对于插入一条数据而言的&#xff0c;如果插入数据之前&#xff0c;没有这条数据&#xff0c;则会插入该条数据&#xff1b;如果插入数据之前就存在这条数据&#xff08;索引值&#xff09;&#xff0c;就更新这条记录。 创建结构体 …

tar文件覆盖漏洞 CVE-2007-4559

文章目录 前言原理例题 [NSSRound#7 Team]新的博客方法一 手搓文件名方法二 python脚本 前言 做到[NSSRound#6 Team]check(Revenge)时发现是tar文件覆盖&#xff0c;但是对概念和执行过程理解不够深就光光记住脚本&#xff0c;所以在做本题[NSSRound#7 Team]新的博客时打算重新…

Linux中的文件IO

文章目录 C语言文件操作系统文件I/O接口介绍 open函数返回值文件描述符fd0 & 1 & 2文件描述符的分配规则 重定向使用 dup2 系统调用 FILE理解文件系统理解硬链接软链接acm 动态库和静态库静态库与动态库生成静态库生成动态库&#xff1a; C语言文件操作 先来段代码回顾…

DouyinAPI接口系列丨Douyin商品详情数据接口丨Douyin视频详情数据接口

抖音商品详情API是抖音开放平台提供的一套API接口&#xff0c;用于获取商品详情信息。通过该API&#xff0c;开发者可以获取到商品的详细信息&#xff0c;包括商品ID、名称、描述、价格、销量、评价等信息。 在使用抖音商品详情API之前&#xff0c;需要先注册并登录抖音开放平…

【Linux】基本指令(上篇)

这里是目录 前言ls指令pwd指令mkdir指令&#xff08;重要&#xff09;tree指令cd指令结合 touch指令rmdir指令&#xff08;重要&#xff09;rm指令&#xff08;重要&#xff09;*通配符man指令&#xff08;重要&#xff09;echo指令cat指令cp指令&#xff08;重要&#xff09;拷…

Linux系统之部署Plik临时文件上传系统

Linux系统之部署Plik临时文件上传系统 一、Plik介绍1.1 Plik简介1.2 Plik特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本 四、下载Plik软件包4.1 创建下载目录4.2 下载Plik软件包4.3 查看下载的Plik软件…

<JavaEE> volatile关键字 -- 保证内存可见性、禁止指令重排序

目录 一、内存可见性 1.1 Java内存模型(JMM) 1.2 内存可见性演示 二、指令重排序 三、关键字 volatile 一、内存可见性 1.1 Java内存模型(JMM) 1&#xff09;什么是Java内存模型&#xff08;JMM&#xff09;&#xff1f;Java内存模型即Java Memory Model&#xff0c;简…

大数据读本:暴雨以数字技术助力传统产业数字化转型

发展数字经济&#xff0c;产业数字化是重要引擎。暴雨作为数字经济的领军企业&#xff0c;近年来积极利用数字技术对传统产业进行全方位、全角度、全链条的改造&#xff0c;提高要素生产率&#xff0c;释放数字对经济发展的放大、叠加、倍增作用。在农业产业化方面&#xff0c;…

无人机助力电力设备螺母缺销智能检测识别,python基于YOLOv7开发构建电力设备螺母缺销小目标检测识别系统

传统作业场景下电力设备的运维和维护都是人工来完成的&#xff0c;随着现代技术科技手段的不断发展&#xff0c;基于无人机航拍飞行的自动智能化电力设备问题检测成为了一种可行的手段&#xff0c;本文的核心内容就是基于YOLOv7来开发构建电力设备螺母缺销检测识别系统&#xf…

基于卷积神经网络的肺炎影像分类分割智能诊断系统

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义&#xff1a; 肺炎是一种常见的呼吸系统感染疾病&#xff0c;其主要病因包括细菌、病毒和真菌等。肺炎的早期诊断对于患者的治疗和预后至关重要。传统的肺炎诊断方…

Your anti-virus program might be impacting your build performance

Your anti-virus program might be impacting your build performance.解决方案 在使用 AndroidStudio 时&#xff0c;经常会弹出框提示&#xff1a;Your anti-virus program might be impacting your build performance. Android Studio checked the following directories: …

Java高级技术-反射

认识反射、获取类 获取类的方法 获取类的构造器 获取类的构造器、并对其进行操作 获取构造器的作用&#xff1a;依然是初始化对象返回 获取成员变量 获取成员变量的方法 获取成员变量的作用&#xff1a;赋值、取值 获取类的成员方法 方法 作用&#xff1a;依然是执行 作用、…

每日一练2023.12.2——正整数A+B【PTA】

题目链接&#xff1a;L1-025 正整数AB 题目要求&#xff1a; 题的目标很简单&#xff0c;就是求两个正整数A和B的和&#xff0c;其中A和B都在区间[1,1000]。稍微有点麻烦的是&#xff0c;输入并不保证是两个正整数。 输入格式&#xff1a; 输入在一行给出A和B&#xff0c;…

Wireshark使用详解

wireshark简介 wireshark是捕获机器上的某一块网卡的网络包&#xff0c;当你的机器上有多块网卡的时候&#xff0c;你需要选择一个网卡。   wireshark能获取HTTP&#xff0c;也能获取HTTPS&#xff0c;但是不能解密HTTPS&#xff0c;所以wireshark看不懂HTTPS中的内容&#…

强化学习(一)——基本概念及DQN

1 基本概念 智能体 agent &#xff0c;做动作的主体&#xff0c;&#xff08;大模型中的AI agent&#xff09; 环境 environment&#xff1a;与智能体交互的对象 状态 state &#xff1b;当前所处状态&#xff0c;如围棋棋局 动作 action&#xff1a;执行的动作&#xff0c;…

Swagger——接口文档自动生成和测试

目录 1 介绍2 使用步骤 1 介绍 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(https://swagger.io/)。 它的主要作用是&#xff1a; 使得前后端分离开发更加方便&#xff0c;有利于团队协作 接口的文档在线自动生成&…

SALib敏感性分析入门实践笔记

1. 敏感性分析 敏感性分析是指从定量分析的角度研究有关因素发生某种变化对某一个或一组关键指标影响程度的一种不确定分析技术。 其实质是通过逐一改变相关变量数值的方法来解释关键指标受这些因素变动影响大小的规律。 敏感性因素一般可选择主要参数&#xff08;如销售收入、…