《堆排序》与《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

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

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

相关文章

探索设计模式的魅力:一次设计,多次利用,深入理解原型模式的设计艺术

原型模式是一种设计模式&#xff0c;属于创建型模式的一种&#xff0c;它用于创建重复的对象&#xff0c;同时又能保持性能。在原型模式中&#xff0c;通过复制现有对象的原型来创建新对象&#xff0c;而不是通过实例化类来创建对象。这样做可以避免耗费过多的资源开销&#xf…

第二节 K8S 的架构

第二节 K8S 的架构 K8S 架构图如下: 官方文档: https://kubernetes.io/docs/concepts/architecture/ kube-api-server 是集群的核心&#xff0c; 是k8s中最重要的组件&#xff0c; 因为它是实现声明式api的关键, 整个集群的入口,所有请求都要经过它, api接口服务. kubernetes…

Navicat使用HTTP通道连接远程服务器的SQLite文件

拷贝ntunnel_sqlite.php文件到Linux机器中 ntunnel_sqlite.php文件位置&#xff1a; 在Navicat安装位置中可以找到ntunnel_sqlite.php文件&#xff0c;其他两个类似文件是支持MySQL和pgsql的

【开源】基于JAVA+Vue+SpringBoot的高校宿舍调配管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能需求2.1 学生端2.2 宿管2.3 老师端 三、系统展示四、核心代码4.1 查询单条个人习惯4.2 查询我的室友4.3 查询宿舍4.4 查询指定性别全部宿舍4.5 初次分配宿舍 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的…

k8s之包管理器Helm

helm的作用就是通过打包的方式&#xff0c;把deployment service ingress这些打包在一块&#xff0c;一键式的部署服务。类似yum官方提供的一个类似与安装仓库的功能&#xff0c;可以实现一键化部署应用。 Helm的三个重要概念 ●Chart&#xff1a;Helm 的软件包&#xff0c;采…

从物联网看智慧文旅的未来:技术与实践的完美结合,重塑旅游体验的新篇章

一、物联网技术&#xff1a;智慧文旅的基石 随着科技的飞速发展&#xff0c;物联网技术已经深入到我们生活的方方面面&#xff0c;尤其在智慧文旅领域&#xff0c;物联网技术更是起到了不可或缺的作用。它如同智慧文旅的基石&#xff0c;为旅游行业带来了前所未有的创新和变革…

node.js(express.js)+mysql实现新增文章分类功能

表单验证 // 导入定义验证规则的包 // const joi require("hapi/joi"); const joi require("joi"); /*** string()值必须是字符串* alphanum()值只能包含a-zA-ZO-9的字符串* min(length) 最小长度* max(length) 大长度* required() 值是必填项&#xff0…

VSCode插件 —— Cody AI (免费AI助手!)

之前介绍过一款 阿里云免费的AI开发工具——通义灵码 TONGYI Lingma 本文再推荐一个可以极大提高开发前端开发效率的工具 —— Cody AI &#xff08;Sourcegraph&#xff09;&#xff0c;同样是免费的&#xff01; 不过&#xff0c;使用Cody AI需要有github 或 Google 、 git…

cadence中统计高电平波形的两种方法(transient measurement和value cross函数)

cadence中统计高电平波形的两种方法&#xff08;transient measurement和value cross函数&#xff09; 一、measurement——transient measurement 如图&#xff0c;为比较器的输出 选择想要查看的波形&#xff0c;右侧会出现对此波形上升沿下降沿的统计结果&#xff0c;如图…

基于时空模型的视频异常检测

假设存在一个运动区域&#xff0c;规则要求只能进行特定的运动项目。 出于安全原因或因为业主不喜欢而禁止进行任何其他活动:)。 我们要解决的问题是&#xff1a;如果我们知道正确行为的列表&#xff0c;我们是否可以创建一个视频监控系统&#xff0c;在出现不常见的行为发出通…

使用WAF防御网络上的隐蔽威胁之目录穿越

目录穿越&#xff08;Directory Traversal&#xff09;是一种网络安全攻击手段&#xff0c;也被称为路径穿越。 这种攻击允许攻击者访问存储在Web服务器文件系统上的文件和目录&#xff0c;这些文件和目录原本不应该对用户可见或可访问。 通过利用安全漏洞&#xff0c;攻击者…

黑马axios案例之地区查询

查询某个省内某个城市的所有地区 接口&#xff1a;http://hmajax.itheima.net/api/area 参数名: pname:省份名字或直辖市名字&#xff0c;比如北京、福建省、辽宁省… cname:城市名字&#xff0c;比如北京市、厦门市、大连市… <!DOCTYPE html> <html lang"en&q…

白话Kubernetes网络

1 Kubernetes 网络介绍 Kubernetes 网络是一个系统&#xff0c;能够使不同集群内外的组件相互通信。这个系统会处理许多情况&#xff0c;其中重要的情况包括 Pod 之间的通信、Service 的通信以及集群如何处理来自外部的流量。 由于 Kubernetes 是分布式系统&#xff0c;因此它…

Git 版本控制 常用操作和项目应用

一、前言 1、何为版本控制&#xff1f; 版本控制是一种记录一个或若干文件内容变化&#xff0c;以便将来查阅特定版本修订情况的系统。 Git是目前最先进的分布式版本控制系统。 maven&#xff1a;jar包管理工具 版本管理工具&#xff1a;Git、Svn 2、Git & SVN对比 …

VUE项目目录与运行流程(VScode)

各目录对应名称含义 main.js&#xff08;导入App.vue&#xff0c;基于App.vue创建结构渲染index.html&#xff09; //核心作用&#xff1a;导入App.vue&#xff0c;基于App.vue创建结构渲染index.html//1.导入Vue核心包 import Vue from vue//2.导入App.vue根组件 import App f…

QT开发低功耗蓝牙BLE连接ECB02模块进行数据收发

时间记录&#xff1a;2024/1/22 一、注意点 &#xff08;1&#xff09;pro文件中引入bluetooth模块 &#xff08;2&#xff09;安卓端运行时需要同步打开定位功能才能扫描到蓝牙设备 &#xff08;3&#xff09;mingw套件不能在Windows上运行&#xff0c;需要使用MSVC套件编译…

UE5 C++学习笔记 FString FName FText相互转换

1.FString 是UE里的String。最接近std::string, 唯一可以修改的字符串类型。性能更低 TEXT(string) TEXT宏&#xff0c;作用是将字符串转换成Unicode&#xff0c;切记UE中使用字符串输出要使用该宏 2. FName 是UE里特有的类型。它更注重于表示名称不区分大小写&#xff0c;不…

c++学习第十一讲---文件操作

文件操作&#xff1a; c中对文件操作需要包含头文件 < fstream > 文本文件&#xff1a;以ASCII码形式储存 二进制文件&#xff1a;以二进制文件储存&#xff08;读不懂&#xff09; 操作文件三大类&#xff1a; 读&#xff1a;ifstream ; 写&#xff1a;ofstream ; 读…

旅游网站day13

1. 完善首页 1.1 首页banner查询接口 1.2 搜索服务 集成ES 1. 方式1&#xff1a;数据独立存储与独立搜索 2. 方式2&#xff1a;条件搜索与主键查询为搜索模块搭建一个服务 为什么需要api? 因为搜索也需要模型对象。 导入es依赖&#xff1a; 搜索api&#xff1a; ES工具类…

《WebKit 技术内幕》学习之十(1): 插件与JavaScript扩展

虽然目前的浏览器的功能很强 &#xff0c;但仍然有其局限性。早期的浏览器能力十分有限&#xff0c;Web前端开发者希望能够通过一定的机制来扩展浏览器的能力。早期的方法就是插件机制&#xff0c;现在流行次啊用混合编程&#xff08;Hybird Programming&#xff09;模式。插件…