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

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

  • 堆排序:
    运用堆的思想进行排序,时间复杂度为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 datasrand(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 datasrand(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.hqwc.cn/news/239336.html

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

相关文章

【FGKASLR绕过】2020 hxpctf - kernel rop

前言 本题说难不难&#xff0c;说简单不简单。说简单是因为题目就是一个简单的栈溢出读写&#xff0c;说难是因为不了解 FGKASLR 保护机制。 一开始没注意开了 FGKASLR&#xff0c;结果一直报错&#xff0c;然后在报错信息中发现其说我指定的 commit_creds 的地址不可执行&am…

C语言--每日选择题--Day32

如果大家对读研究生和就业不知道如何抉择&#xff0c;我的建议是看大家的经济基础&#xff0c;如果家里不是很需要你们工作&#xff0c;就读研提升自己的学历&#xff0c;反之就就业&#xff1b;毕竟经济基础决定上层建筑&#xff1b; 第一题 1. 下面代码的结果是&#xff1a;…

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

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

用100ask 6ull配合 飞凌 elf1的教程进行学习的记录

启动方式 百问网 elf1: 固件 emmc-otg 串口 网络 改eth0, 网线接在右边的网口eth2上

Trie字符串统计(字典树的插入与查找)

题目&#xff1a; 插入模拟&#xff1a;假如现在要依次插入cat,car,busy,cate,bus,car 查找&#xff1a; 代码&#xff1a; import java.util.Scanner;public class Main {public static int[][] chnew int[100010][26];public static int[] cntnew int[100010];public static…

【总结】二次曲面的和正负惯性指数

最难记得就是单叶双曲面和双叶双曲面&#xff0c;我的方法是**“负担”&#xff0c;负惯性指数的个数为单个就是单叶双曲面。** 特别要注意&#xff0c;这里的等号右边是正数&#xff0c;如果是负数要两边同时乘以一个负一。

【鸿蒙应用ArkTS开发系列】-自定义底部菜单列表弹窗

文章目录 前言创建Demo工程创建dialog 文件夹创建ListMenu 接口创建自定义弹窗 ListMenuDialog使用自定义弹窗 打包测试效果演示默认效果菜单带图标效果设置文本颜色效果不同文本颜色效果无标题效果 前言 上一篇文章中我们实现了选择图片、选择文件、拍照的功能 。 链接在这里…

第二节:服务拆分(案例)

一、服务拆分注意事项 1.1 拆分原则 每个微服务&#xff0c;不要重复开发相同业务&#xff08;例如在单体项目中用到了一个查询&#xff0c;这个查询功能能够查询出订单信息、商品信息、用户信息&#xff0c;那么在拆分微服务时就不要将其写在一起了&#xff0c;订单的微服务只…

【web安全】ssrf漏洞的原理与使用

前言 菜某对ssrf漏洞的总结。 ssrf的作用 主要作用&#xff1a;访问外界无法访问的内网进行信息收集。 1.进行端口扫描&#xff0c;资源访问 2.指纹信息识别&#xff0c;访问相应的默认文件 3.利用漏洞或者和payload进一步运行其他程序 4.get类型漏洞利用&#xff0c;传参数…

将不同时间点的登录状态记录转化为不同时间段的相同登录状态SQL求解

题目 有不同时间点的登录状态记录表state_log如下 请使用sql将其转化为如下表的不同时间段的相同登录状态记录 思路分析&#xff1a; 此类问题需要用到lag或lead函数取上下行对应的数据&#xff0c;然后对前后结果做比较打标签&#xff08;0或1&#xff09;&#xff0c;再…

富文本内容回显

<el-card><h7>正文内容</h7><template><div v-html"inputForm.bulletinData"></div></template></el-card> 通过 v-html 来回显数据

计算机毕业设计|基于SpringBoot+MyBatis框架健身房管理系统的设计与实现

计算机毕业设计|基于SpringBootMyBatis框架的健身房管理系统的设计与实现 摘 要:本文基于Spring Boot和MyBatis框架&#xff0c;设计并实现了一款综合功能强大的健身房管理系统。该系统涵盖了会员卡查询、会员管理、员工管理、器材管理以及课程管理等核心功能&#xff0c;并且…