【堆】Top-K问题

news2024/12/26 11:07:17

标题C语言库函数scanf()解读

水墨不写bug 


 (图片来源于网络)

正文开始:

        Top-K问题是一类问题的统称:

        即根据对象的某一属性,找出这个属性最突出的K个对象,并且通常对象的数量极大。

(一)构造对象

        为演示方便,通过代码生成一个数据量极大的数据对象:生成1w个数据;如果我们将问题抽象化为找出1w个数据中的最大5个数,那么Top-K问题就切实可见了。

        在你的编译器上输入如下代码并运行,你会发现在同目录下多了一个文件:"data.txt"

#include<stdio.h>
#include<stdlib.h>


void CreateNDate()
{
	// 造数据
	int n = 10000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}

	for (size_t i = 0; i < n; ++i)
	{
		int x = rand() % 1000000;
		fprintf(fin, "%d\n", x);
	}

	fclose(fin);
}

再打开文件,人为的将5个数改写为最大并做好记录。

(二)建堆并解决过程

        打开文件并读入数据,读入并压入k个数据,这时堆内已有k个数据;

        接下来每读入一个数据,就需要堆顶部的数据进行比较;

(找出最大K个数:这种情况需要建立小堆,因为小堆的堆顶数据是这个堆里最小的:最小的数与读入的数进行比较。如果读入的数比较大,就将较小的堆顶交换出去;如果读入的数比较小,就保留堆顶的数据)

(找出最小K个数:这种情况需要建立大堆,因为大堆的堆顶数据是这个堆里最大的:最大的数与读入的数进行比较。如果读入的数比较小,就将较大的堆顶交换出去;如果读入的数比较大,就保留堆顶的数据)

         这样既能利用堆的高效插入和高效删除又避免了开辟大量的空间来存储变量

 


#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int HPDatatype;

typedef struct Heap
{
	HPDatatype* a;
	int size;
	int capacity;
}HP;
void AdgustDown(HPDatatype* a, int n, int parent);

//初始化
void HPinit(HP* php);

//销毁
void HPDestroy(HP* php);

//插入数据
void HPpush(HP* php, HPDatatype x);

//删除数据,规定删除堆顶的数据
void HPpop(HP* php);

//得到堆顶数据
HPDatatype HPtop(HP* php);

//判空
bool HPempty(HP* php);

//数据个数
int HPsize(HP* php);

//初始化
void HPinit(HP* php)
{
	assert(php);
	php->capacity = php->size = 0;//size指向最后一个元素的下一个
	php->a = NULL;
}

//销毁
void HPDestroy(HP* php)
{
	assert(php);
	php->capacity = php->size = 0;
	free(php->a);
}

//交换函数
void Swap(HPDatatype* a,HPDatatype* b)
{
	HPDatatype tem = *a;
	*a = *b;
	*b = tem;
}

//此处模拟实现小堆,小数上移
//参数:
//要插入的数据和孩子节点的数组下标
void AdgustUp(HPDatatype* a,int child)
{
	//根据公式,不论是左孩子还是右孩子,都可以计算得到
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

//插入数据
void HPpush(HP* php, HPDatatype x)
{
	assert(php);
	//如果size == capacity 说明顺序表满了,或者没有一个数据
	if (php->size == php->capacity)
	{
		int Newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDatatype* tem = (HPDatatype*)realloc(php->a, sizeof(HPDatatype)*Newcapacity);
		{
			if (tem == NULL)
			{
				perror("realloc fail!");
				return;
			}
		}
		php->a = tem;
		php->capacity = Newcapacity;
	}

	//开辟好空间后,插入
	php->a[php->size] = x;
	php->size++;
	//向上调整
	AdgustUp(php->a,php->size-1);
}

//向下调整
//参数;
//顺序表,数据总个数,向下调整时目前双亲节点的数组下标
void AdgustDown(HPDatatype* a,int n,int parent)
{
	int child = parent * 2 + 1;
	//目前假设左孩子小
	while (child < n)
	{	//如果右孩子存在,并比左孩子小,选择右孩子
		if (child + 1 < n && a[child] > a[child + 1])
		{
			++child;
		}
		//此时孩子表示较小的孩子
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else {
			break;
		}

	}
}

//删除数据,规定删除堆顶的数据
void HPpop(HP* php)
{
	assert(php);
	Swap(&php->a[0], &php->a[php->size - 1]);
	--php->size;
	AdgustDown(php->a,php->size,0);
}

//得到堆顶数据
HPDatatype HPtop(HP* php)
{
	assert(php);
	return php->a[0];
}

//判空
//若为空,返回真,否则返回假
bool HPempty(HP* php)
{
	assert(php);
	return php->size == 0;
}

//数据个数
int HPsize(HP* php)
{
	assert(php);
	return php->size;
}

int main()
{
	
	//CreateNDate();
	FILE* fin = fopen("data.txt", "r");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}
	int comp = 0;
	HP ph;
	HPinit(&ph);
	int k = 0;
	scanf("%d", &k);
	//刚开始push k次,建堆
	for (int i = 0; i < k; i++)
	{
		fscanf(fin, "%d", &comp);
		HPpush(&ph, comp);
	}
	//开始比较,comp与堆顶数据的大小
	while (fscanf(fin,"%d",&comp) != EOF)
	{
		if (ph.a[0] < comp)
		{
			Swap(&ph.a[0], &comp);
			AdgustDown(ph.a,ph.size,0);
		}
	}
	for (int i = 0; i < k; i++)
	{
		printf("%d ", ph.a[i]);
	}

	return 0;
}

        (注意:        先调用CreateNDate()函数来创建一个数据文件,标记好最大K个数后再运行上述代码来验证。)


完~

未经作者同意禁止转载

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

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

相关文章

Midjourney发布新特性风格参考

1. 引言 最近&#xff0c;Midjourney 推出了Style Reference V2.0 即功能更加强大的风格参考工具&#xff0c;该工具可以让大家参考其他图像的风格&#xff0c;生成与参考图像风格保持一致&#xff0c;与文本提示词语义内容保持一致的图像。它与图像提示类似&#xff0c;但是只…

LightDB24.1 存储过程支持inner和outer对变量的引用

背景 Oracle oracle plsql支持如下场景&#xff1a; 在for循环中&#xff0c;将select查询的结果给一个record类型&#xff0c;这一操作也被称为隐式游标操作。record类型中一个字段用来接收查询结果中的一个select查询语句&#xff08;update,delete,insert在这个语法中都会…

ELK快速搭建图文详细步骤

目录 一、下载地址二、安装docker-compose(已安装则跳过)三、初始化ELK1. 赋予/setup/entrypoint.sh执行权限2. 初始化 docker-elk 所需的 Elasticsearch 用户和组3. 重置默认用户的密码4. 替换配置文件中的用户名和密码5. 重启 Logstash 和 Kibana&#xff0c;使用新密码重新连…

蓝桥杯单片机快速开发笔记——NE555测频

一、原理分析 NE555作为一种多功能集成电路&#xff0c;在信号发生和频率测量方面具有广泛的应用。通过合理配置和连接外部元件&#xff0c;可以实现不同类型的信号发生和频率测量功能。 原理&#xff1a; 信号发生器&#xff1a; NE555可以配置为多种不同的振荡器电路&#x…

鸿蒙Harmony应用开发—ArkTS-转场动画(组件内转场)

组件内转场主要通过transition属性配置转场参数&#xff0c;在组件插入和删除时显示过渡动效&#xff0c;主要用于容器组件中的子组件插入和删除时&#xff0c;提升用户体验。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记…

leetcode代码记录(移除链表元素

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head […

学点Java打小工_Day2Day3_一点作业

1 猜数字&#xff08;10次机会&#xff09; 随机生成[1,1000]的一个数&#xff0c;输入你猜的数程序会给出反馈&#xff0c;直到猜对或次数用尽(10次)。 //猜数字 10次机会Testpublic void guessNumber() {Random random new Random();// [0, 1000) 1// [1, 1000]int num ra…

基于 Echarts + Python Flask ,我搭建了一个动态实时大屏监管系统

一、效果展示 1. 动态实时更新数据效果图 2. 鼠标右键切换主题 二、确定需求方案 支持Windows、Linux、Mac等各种主流操作系统&#xff1b;支持主流浏览器Chrome&#xff0c;Microsoft Edge&#xff0c;360等&#xff1b;服务器采用python语言编写&#xff0c;配置好python环…

linux---文件查找

知识点&#xff1a; whereis 可以搜索传统命令的可执行文件路径和说明文档 which 搜索可执行文件 #whereir包含了which locate 在数据库中进行快速查找 find . -name 文件名/文件名要求 #按文件名查找. -iname 文件名 #按文件名查找且…

【史上最全万字mysql进阶语法】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;书生♡&#xff0c;今天主要和大家分享一下mysql的进阶语法,数据库的分组/分页/排序/子查询以及详细案例&#xff0c;希望对大家有所帮助。 &#x1f49e;&#x1f49e;前路漫漫&#xff0c;希望大家坚持下去&am…

2024年最新Anaconda3 2024版中Jupyter Notebook安装

一、 Anaconda3 2024版下载 1.下载&#xff1a;Free Download | Anaconda 2.等待 解释&#xff1a;默认选择等等下载 &#xff0c;时间可能数分钟 3.安装 解释&#xff1a;打开刚刚下载的Anaconda Navigator&#xff0c;并如图安装低版本&#xff0c;高版本会直接报错 4. …

ES8生产实践——性能压测工具esrally

引言 什么是压测 压测&#xff0c;即压力测试&#xff0c;是指对计算机系统、软件应用或网络服务等进行负载测试&#xff0c;以模拟实际使用场景中的高负载情况&#xff0c;检验系统在压力下的性能、稳定性和可靠性。压测旨在确定系统在正常或极端负载下的性能极限&#xff0…

首个业内DNA存储技术规范发布

在DNA数据存储的检索过程中&#xff0c;采用了三个输入对应一个输出逻辑实现的算法模式来生成数据表示的模式。这一算法模式的设计是为了有效编码和解码存储在DNA分子上的信息。 其中提到的“扰动比例”δ(n)是一个关键概念&#xff0c;它衡量的是在总的细胞数目&#xff08;此…

【MySQL】图形化界面工具DataGrip安装&配置&使用

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

Redis6.0多线程的疑惑解答

1.Redis6.0之前的版本真的是单线程吗&#xff1f; Redis在处理客户端的请求是&#xff0c;包括获取(socket读)、解析、执行、内容返回(socket 写)等都有一个 顺序串行的主线程处理&#xff0c;这就是所谓的"单线程"。但如果严格来讲并不是单线程&#xff0c;除了主线…

2024蓝桥杯每日一题(并查集)

备战2024年蓝桥杯 -- 每日一题 Python大学A组 试题一&#xff1a;奶酪 试题二&#xff1a;合并集合 试题三&#xff1a;连通块中点的数量 试题四&#xff1a;网络分析 试题一&#xff1a;奶酪 【题目描述】 现有一块大奶酪&#xff0c;它的高度为 hℎ…

Java SE入门及基础(44)

目录 I / O流(上) 1. 什么是I / O流 过程分析 I / O的来源 Java 中的 I / O流 2. 字节流 OutputStream 常用方法 文件输出流 FileOutputStream 构造方法 示例 InputStream 常用方法 文件输入流 FileInputStream 构造方法 示例 综合练习 字节流应用场景 Java SE文…

命名空间——初识c++

. 个人主页&#xff1a;晓风飞 专栏&#xff1a;数据结构|Linux|C语言 路漫漫其修远兮&#xff0c;吾将上下而求索 文章目录 经典的Hello Word 起航c关键字c语言的命名冲突问题域作用限定符::命名空间 namespace命名空间定义命名空间的使用1.加命名空间名称及作用域限定符2.使用…

web集群-lvs-DR模式基本配置

目录 环境&#xff1a; 一、配置RS 1、安装常见软件 2、配置web服务 3、添加vip 4、arp抑制 二、配置LVS 1、添加vip 2、安装配置工具 3、配置DR 三、测试 四、脚本方式配置 1、LVS-DR 2、LVS-RS 环境&#xff1a; master lvs 192.168.80.161 no…

数据结构与算法4-冒泡排序

文章目录 1. 认识冒泡排序2. 图示2.1 图示12.2 图示2 3. 代码 1. 认识冒泡排序 双层for循环&#xff0c;每次选出最大的数“浮”到数组的最后面&#xff1b;时间复杂度O( n 2 n^2 n2)&#xff0c;空间复杂度O(1);重复地遍历待排序的数列&#xff0c;一次比较两个元素&#xff…