《堆排序》与《Top—k》

目录

​编辑

前言:

关于《堆排序》:

第一步:建堆

第二步:排序

《Top—K问题》

关于Top—k问题:


前言:

我们在前面的blog中,对于《堆》已经有了初步的概念,那么接下来我们可以利用《堆》来解决我们日常生活中存在的问题,本篇我们给出两个常用的应用场景,分别是《排序》以及《Top—k问题》,上一篇blog在:《堆》的模拟实现-CSDN博客

 

关于《堆排序》:

#define _CRT_SECURE_NO_WARNINGS  1
#include<stdio.h>void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void AdjustDown(int* arr, int sz, int parent)
{int child = parent * 2 + 1;while (child < sz){if (child + 1 < sz && arr[child] < arr[child + 1]){child++;}if (arr[child] > arr[parent]){swap(&arr[child], &arr[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}void AdjustUp(int* arr, int sz, int child)
{while (child > 0){int parent = (child - 1) / 2;if (arr[parent] < arr[child]){swap(&arr[parent], &arr[child]);}child = parent;}
}int main()
{int arr[] = { 2, 6, 9, 3, 1, 7 };int sz = sizeof(arr) / sizeof(arr[0]);for (int i = (sz - 1 - 1) / 2; i >= 0; i--){AdjustDown(arr, sz, i);}//向下调整算法//for (int i = 1; i<sz; i++)//{//	AdjustUp(arr, sz, i);//}//向上调整算法int end = sz - 1;while (end > 0){swap(&arr[0], &arr[end]);AdjustDown(arr, end, 0);--end;}return 0;
}

第一步:建堆

利用《堆》可以方便我们对一个给定的乱序数组实现排序,首先我们应当选择大堆来进行排序操作。

为什么我们不选择使用小堆来进行建堆呢?

通过之前对《堆》的blog说明,小堆就是对顶元素为最小元素,其他的节点数都比第一个元素小,那么如果是小堆,最小的数字已经就是第一个元素,若要找出次小的元素,则又需要在剩下的元素中再进行建堆,重复循环才能完成排序,这样子的时间复杂度高,不利于排序。

因此我们选择利用大堆来建堆,实现大堆后,再将首尾的元素进行交换,再利用向下调整法调整法对剩下的n-1个元素进行调整,再进行交换,如此能实现排序。

    int arr[] = { 2, 6, 9, 3, 1, 7 };int sz = sizeof(arr) / sizeof(arr[0]);for (int i = 1; i<sz; i++){AdjustUp(arr, sz, i);}

对如图的数组进行向上 调整法建堆:

 

第二步:排序

 首先我们将首尾元素进行交换:

对除最后一个元素外的其他元素进行向下调整法,将其继续成大堆

 

 

 

 

重复上述步骤

最终可得堆为:

 

如此则完成了堆排序。

 

《Top—K问题》

关于Top—k问题:

即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。我们以求n个数据中前K个最大的元素为例进行说明:(假设n=10000) (假设k=10)

 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
const char* file = "data.txt";
void swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void AdjustDown(int* arr, int sz, int parent)
{int child = 2 * parent + 1;while (child < sz){if (child + 1 < sz && arr[child + 1] < arr[child]){child++;}if (arr[child] < arr[parent]){swap(&arr[child], &arr[parent]);parent = child;child = 2 * parent + 1;}else{break;}}
}void CreateFile()
{//创建随机数的种子srand((unsigned int)time(NULL));FILE* Fin = fopen(file, "w");if (Fin == NULL){perror("Fopen error");exit(-1);}int n = 10000000;for (int i = 0; i < n; i++){int x = (rand() + i) % n;fprintf(Fin, "%d\n", x);}fclose(Fin);Fin = NULL;
}void Print()
{FILE* Fout = fopen(file, "r");if (Fout == NULL){perror("Fout error");exit(-1);}//取前k个数进小堆int* minheap = (int*)malloc(sizeof(int) * 5);if (minheap == NULL){perror("minheap -> malloc");return;}for (int i = 0; i < 5; i++){fscanf(Fout, "%d", &minheap[i]);}for (int i = (5-1-1)/2; i >=0; --i){AdjustDown(minheap, 5, i);}//读取数据int x = 0;while (fscanf(Fout, "%d", &x) != EOF){if (minheap[0] < x){minheap[0] = x;}AdjustDown(minheap, 5, 0);}for (int i = 0; i < 5; i++){printf("%d ", minheap[i]);}fclose(Fout);Fout = NULL;
}int main()
{//CreateFile();Print();return 0;
}

首先我们先创建10000000个随机数,再对其中的数字进行修改,随机抽5个数,分别修改为

10000001,10000002,10000003,10000004,10000005

再建一个小堆,注意,这里一定是小堆!

如果建的是大堆,若数据先搜索到了10000005,那么该数字一定是在堆顶,当我们查找到次小的数字后,却无法进堆,所以我们采用小堆!

 然后将数据的前5个元素进入小堆中,

再对剩下的9999995个数进行遍历和比较,若大于堆顶元素,则直接替换。

替换完后再进行一次向下调整,当遍历完整个数据后,堆中就是插入的

 10000001,10000002,10000003,10000004,10000005

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

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

相关文章

SpringCloud系列篇:核心组件之网关组件

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于SpringCloud的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.网关组件是什么 二. 网关组件的…

大模型第三节课程笔记

大模型开发范式 优点&#xff1a;具有强大语言理解&#xff0c;指令跟随&#xff0c;和语言生成的能力&#xff0c;具有强大的知识储备和一定的逻辑推理能力&#xff0c;进而能作为基座模型&#xff0c;支持多元应用。 不足&#xff1a;大模型的知识时效性受限&#xff0c;大模…

在Ubuntu中检查内存的五个命令,总有一种适合你

序言 作为Ubuntu用户,尤其是管理员,我们需要检查系统使用了多少内存资源,以及有多少是可用的。我们还知道,大多数管理任务最好从Linux命令行完成,而不是从图形用户界面完成。例如,服务器通常在shell上工作,没有图形用户界面。由于控制服务器上的内存资源是最重要的,因…

人工智能图像生成的道德利弊

目录 一、我们应该关注人工智能图像吗&#xff1f;二、利用人工智能增强创造力的积极作用三、版权和剽窃问题四、对就业和劳动力动态的影响五、无意识的偏见和影响六、负责任地前行 人工智能&#xff08;AI&#xff09;发展迅速&#xff0c;尤其是近年来。据估计&#xff0c;超…

利用“与非”运算实现布尔代数中的与,或,非三种运算

什么是“与非”运算&#xff1f; 要想明白“与非”运算&#xff0c;首先要明白“与”运算和“非”运算。 “与”运算在离散数学中叫做合取式&#xff0c;也就是A和B相同时为1的时候结果才为1&#xff0c;其余情况都为0 下面是“与”运算的真值表 “非”运算在离散数学中叫做否…

对话北京菜百电子商务有限公司总经理张梦轩:品牌自播引领直播的时代即将来临

整理 | 飞族 编辑 | 渔舟 出品&#xff5c;极新&#xff06;北京电子商务协会 作为一种新型又高效的场域&#xff0c;在直播电商场景下&#xff0c;品牌通过尝试运用AI、VR、数字人等新技术&#xff0c;制作专业内容&#xff0c;去更好地吸引和打动消费者&#xff0c;促进业…

【S32K 进阶之旅】 NXP S32K3 以太网 RMII 接口调试(2)

前言 前文介绍了 NXP S32K3 以太网 RMII 接口调试的开发环境搭建&#xff0c;下面开始详解软件调试步骤。没看过第一节的小伙伴请移步《【S32K 进阶之旅】 NXP S32K3 以太网 RMII 接口调试&#xff08;1&#xff09;》&#xff0c;话不多说我们直接进入正题。 lwip Stack 介绍 …

双指针(简化哈希)力扣15.三数之和

题目 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 …

Linux Capabilities 进阶实战

目录 1. 快速回顾 2. 为可执行文件分配 capabilities 3. 构建半特权环境 4. 容器与 capabilities Linux Capabilities 基础概念与基本使用 上一篇学习了LinuxCapabilities的基础知识和基本使用&#xff0c;因为后面需要学习Docker的逃逸&#xff0c;理解Linux Capabilitie…

网工内推 | 运维工程师,国企、上市公司,RHCE认证优先

01 广东机场白云信息科技股份有限公司 招聘岗位&#xff1a;基础架构运维工程师&#xff08;中级&#xff09; 职责描述&#xff1a; 1、参与公司业务系统的监控、巡检、维护、故障定位、原因分析&#xff1b; 2、负责业务系统的上线、升级割接工作&#xff1b; 3、负责服务器…

作业--day43

使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数&#xff0c;将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c…

python 基础笔记

基本数据类型 函数 lamda 匿名函数 成员方法 类 类与对象 构造方法 魔术方法 私有成员 私有方法 继承 注解 变量注解 函数注解 Union类型 多态 参考链接&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了_哔哩哔哩_bilib…