堆的实现-向上调整算法-向下调整算法-堆排序-TopK问题 C语言

news2025/1/4 19:04:35

一、堆的概念及结构

二、 向上调整算法

注意:循环条件不可写parent > 0

//向上调整算法
//child为下标
void adjustup(int* 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;
		}
		
	}
}

 三、向下调整算法

他的时间复杂度比向上调整算法要更低,因此尽可能用向下调整算法

//向下调整算法
//n为数据个数,parent为下标
void adjustdown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;;
		}
		else
		{
			break;
		}

	}
}

四、完整的堆的实现

Heap.h 

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<assert.h>
#include<stdbool.h>

//小堆
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;

void HeapInit(Heap* hp);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
bool HeapEmpty(Heap* hp);

heap.c

#include"Heap.h"

void HeapInit(Heap* hp)
{
	assert(hp);
	hp->_a = NULL;
	hp->_capacity = 0;
	hp->_size = 0;
}
// 堆的销毁
void HeapDestory(Heap* hp)
{
	assert(hp);
	free(hp->_a);
	hp->_a = NULL;
	hp->_capacity = 0;
	hp->_size = 0;
}// 堆的判空
bool HeapEmpty(Heap* hp)
{
	assert(hp);
	return 0 == hp->_size;
}
void swap(HPDataType* p1, HPDataType* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
//向上调整算法
//child为下标
void adjustup(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;
		}
		
	}
}
//向下调整算法
//n为数据个数,parent为下标
void adjustdown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;;
		}
		else
		{
			break;
		}

	}
}
// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);
	if (hp->_capacity == hp->_size)
	{
		int newcapacity = (hp->_capacity == 0 ? 4 : hp->_capacity * 2);
		HPDataType* tmp = (HPDataType*)realloc(hp->_a, sizeof(HPDataType) * newcapacity);
		if(NULL == tmp)
		{
			perror("HeapPush realloc fail!!");
			return;
		}
		hp->_a = tmp;
		hp->_capacity = newcapacity;
	}
	hp->_a[hp->_size] = x;
	hp->_size++;
	adjustup(hp->_a, hp->_size - 1);
}
// 堆的删除,指删除顶部数据
void HeapPop(Heap* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));
	swap(&hp->_a[0], &hp->_a[hp->_size - 1]);
	hp->_size--;

	adjustdown(hp->_a, hp->_size, 0);

}
// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
	assert(hp);
	assert(!HeapEmpty(hp));
	return hp->_a[0];
}
// 堆的数据个数
int HeapSize(Heap* hp)
{
	assert(hp);
	return hp->_size;
}



heaptest.c 

#include"Heap.h"

void test()
{
	Heap hpp;
	HeapInit(&hpp);
	int aa[] = { 65,100,70,32,50,60 };
	for (int i = 0; i < sizeof(aa) / sizeof(int); ++i)
	{
		HeapPush(&hpp, aa[i]);
	}
	while(!HeapEmpty(&hpp))
	{
		int top = HeapTop(&hpp);
		printf("%d\n", top);
		HeapPop(&hpp);
	}
	HeapDestory(&hpp);
}
typedef int datatype;
//利用向上调整建堆
//n为元素个数
void CreatHeapByadjustup(datatype* a, int n)
{
	
	int i = 0;
	for (i = 1; i< n; i++)
	{
		adjustup(a, i);
	}
}
//利用向下调整建堆
// 他的时间复杂度更低
//n为元素个数
void CreatHeapByadjustdown(datatype* a, int n)
{
	int i = 0;
	//叶子结点无法下调整,所以传入最后一个父亲
	//最后一个父亲等于元素个数(n - 1 - 1) / 2
	for (i = (n - 2) / 2; i >= 0; i--)
	{
		adjustdown(a, n, i);
	}
}
//堆排序
//n为元素个数
void HeapSort(datatype* a, int n)
{
	//利用向下调整建堆
	CreatHeapByadjustdown(a, n);
	int end = n - 1;
	while (end)
	{
		swap(&a[0], &a[end]);
		end--;
		//将数组第一个元素放到合适位置,重新变为堆
		adjustdown(a, end, 0);
	}
}
//int main()
//{
//	//test();
//	//利用向上调整建堆
// 	//int aa[] = { 65,100,70,32,50,60 };
//	//利用向上调整建堆
//	//CreatHeapByadjustup(aa, sizeof(aa) / sizeof(int));
//	//利用向下调整建堆
//	//CreatHeapByadjustdown(aa, sizeof(aa) / sizeof(int));
//	//堆排序,
//	//想要获得降序,就要建立小堆
//	//因为建立小堆可以取出最小的值放到数组尾部,然后再建小堆,
//	//同样想要获得降升序,就要建立大堆
//	//HeapSort(aa, sizeof(aa) / sizeof(int));
//
//	
//	return 0;
//}

 五、堆排序

        想要获得降序,就要建立小堆,因为建立小堆可以取出最小的值放到数组尾部,然后再建小堆,同样想要获得降升序,就要建立大堆

//利用向上调整建堆
//n为元素个数
void CreatHeapByadjustup(datatype* a, int n)
{
	
	int i = 0;
	for (i = 1; i< n; i++)
	{
		adjustup(a, i);
	}
}
//利用向下调整建堆
// 他的时间度更低
//n为元素个数
void CreatHeapByadjustdown(datatype* a, int n)
{
	int i = 0;
	//叶子结点无法下调整,所以传入最后一个父亲
	//最后一个父亲等于元素个数(n - 1 - 1) / 2
	for (i = (n - 2) / 2; i >= 0; i--)
	{
		adjustdown(a, n, i);
	}
}
//堆排序
//n为元素个数
void HeapSort(datatype* a, int n)
{
	//利用向下调整建堆
	CreatHeapByadjustdown(a, n);
	int end = n - 1;
	while (end)
	{
		swap(&a[0], &a[end]);
		end--;
		//将数组第一个元素放到合适位置,重新变为堆
		adjustdown(a, end, 0);
	}
}
int main()
{
	test();
	//利用向上调整建堆
 	int aa[] = { 65,100,70,32,50,60 };
	//利用向上调整建堆
	CreatHeapByadjustup(aa, sizeof(aa) / sizeof(int));
	//利用向下调整建堆
	CreatHeapByadjustdown(aa, sizeof(aa) / sizeof(int));
	//堆排序,
	//想要获得降序,就要建立小堆
	//因为建立小堆可以取出最小的值放到数组尾部,然后再建小堆,
	//同样想要获得降升序,就要建立大堆
	HeapSort(aa, sizeof(aa) / sizeof(int));
	return 0;
}

六、Top-K 问题

Top-k问题:
     假设有10万亿数据,取k个最大的.数据量很大,就不可以把数都存进去,因为存储空间不允许
    解决思路:

        那么我们就开辟K个空间的数组,插入K个数据建小堆, 然后再插入就和堆中最小数(数组第一个数)进行比较,堆中最小数比较小,就插入代替他,利用堆排序,重新将鼠标变为堆,当遍历完所有数据,数组中存放的就是最大的K个数字

注:adjustdown()函数在前面堆的实现有

/为了方便直接观察,我们可以创造数据
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);
}

void PrintTopK(int k)
{
	const char* file = "data.txt";
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen error");
		return;
	}

	int* kminheap = (int*)malloc(sizeof(int) * k);
	if (kminheap == NULL)
	{
		perror("malloc error");
		return;
	}
	//读取前k个数据
	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &kminheap[i]);
	}

	// 将10个数据建小堆
	for (int i = (k - 1 - 1) / 2; i >= 0; i--)
	{
		adjustdown(kminheap, k, i);
	}
	//之后的插入
	int val = 0;
	while (!feof(fout))
	{
		fscanf(fout, "%d", &val);
		if (val > kminheap[0])
		{
			kminheap[0] = val;
			adjustdown(kminheap, k, 0);
		}
	}

	for (int i = 0; i < k; i++)
	{
		printf("%d ", kminheap[i]);
	}
	printf("\n");
}
int main()
{
	//创造第一次之后,就注释,
	//然后打开文件手动将4个数改为最大的再次运行
	CreateNDate();
	PrintTopK(5);

	return 0;
}

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

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

相关文章

免费开源的私人笔记项目,极空间搭建全平台笔记和待办事项『Joplin』

免费开源的私人笔记项目&#xff0c;极空间搭建全平台笔记和待办事项『Joplin』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 我想很多小伙伴都有记录笔记或者备忘的习惯&#xff0c;其实目前市面可用的这类应用还是很多的&#xff0c;比如印象笔记&#xff0c;有道云笔记。作为…

文件解析漏洞集合

IIS解析漏洞 IIS6 目录解析 在网站下建立文件夹的名字为.asp/.asa 的文件夹&#xff0c;其目录内的任何扩展名的文件都被IIS当作asp 文件来解析并执行。 这里显示的是 1.asp下的1.jpg&#xff0c;按照道理来说里面的文件是一个图片&#xff0c;但是访问的话&#xff0c;会出…

SpringBoot面试题整理(1)

面试整理 前置知识 ApplicationContextInitializerApplicationListenerBeanFactoryBeanDefinitionBeanFactoryPostProcessorAwareInitializingBean/DisposableBeanBeanPostProcessor 面试题 SpringBoot启动流程IOC容器初始化流程Bean声明周期Bean循环依赖SpringMVC执行流程…

JavaEE 初阶(13)——多线程11之“定时器”

目录 一. 什么是“定时器” 二. 标准库的定时器 三. 定时器的实现 MyTimer 3.1 分析思路 1. 创建执行任务的类。 2. 管理任务 3. 执行任务 3.2 线程安全问题 四. 拓展 一. 什么是“定时器” 定时器是软件开发中的一个重要组件&#xff0c;类似于一个“闹钟”&#xff0…

【Spring】详细理解Spring中控制反转(IOC)和依赖注入(DI)的设计思想。

目录 1.相关概念 2. 设计IOC容器的两个主要接口 2.1 BeanFactory接口 2.2 ApplicationContext接口 2.3 两个接口的区别【面试题】 3. Bean对象的管理&#xff08;控制反转&#xff09; 3.1 基于XML文件管理bean对象 3.2 基于注解方式去管理【重点】 4. 依赖注入&#…

81.WEB渗透测试-信息收集-框架组件识别利用(5)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;80.WEB渗透测试-信息收集-框架组件识别利用&#xff08;4&#xff09; solr&#xff1a;…

第三方库jsoncpp

文章目录 0.jsoncpp库是做什么的&#xff1f;1.安装库2.有哪几个类&#xff0c;如何使用Json::Value类Json::Writer类-StreamWriterJson::Reader类-CharReader三者关系 3.使用样例将数据先存入Value类&#xff0c;再通过StreamWriter类转为Json格式的字符串获取到Json格式字符串…

6 postgresql事务与并发控制

事务与并发控制 事务可以理解为做一件事&#xff0c;数据库就是一件事要么做完&#xff0c;要么不做&#xff0c;不然这数据库给给人不可靠的感觉 正如解释事务具有四个重要特性&#xff1a;ACID&#xff08;原子性&#xff0c;一致性&#xff0c;隔离性&#xff0c;持久性&a…

python实现提取视频帧的图片

文章目录 1、需求痛点2、完整代码⭐3、代码分析3.1、需要改动的地方3.2、OpenCV库的使用3.3、多线程技术 4、执行效率5、效果展示⭐6、注意事项&#x1f53a;7、总结 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注…

3 IIC总线

3 IIC总线 1、基本概念1.1 IIC总线定义1.2 IIC总线协议概念 2 以AT24C02为例说明时序2.1 基本特性2.2 利用GPIO模拟IIC2.3 对AT24C02的操作2.4 重定向printf 1、基本概念 1.1 IIC总线定义 定义&#xff1a;两线式串行总线 两线式&#xff1a;说明处理器和外设之间只需两根信号…

【时间复杂度和空间复杂度】(内含超多实例练习)

【时间复杂度和空间复杂度】&#xff08;内含超多实例练习&#xff09; 1. 算法效率2. 时间复杂度2.1 时间复杂度的概念2.2 实例练习2.2.1 数组中搜索数据2.2.2 冒泡排序2.2.3 二分查找2.2.4 阶乘递归2.2.5 斐波那契递归 3. 空间复杂度3.1 空间复杂度的概念3.2 实例练习3.2.1 冒…

Set Hashset底层原理 LinkedSet底层原理 Treeset 31

不重复只执行一次&#xff0c;排序是小到大&#xff0c;色图是接口类 Hashset底层原理 LinkedSet底层原理 Treeset 总结

AI+云边端协同,EasyCVR视频汇聚技术赋能安防监控新生态

随着信息技术的飞速发展和数字化时代的到来&#xff0c;安防监控领域的技术也在不断创新和突破。EasyCVR平台的视频汇聚技术作为其中的佼佼者&#xff0c;以其强大的视频处理、汇聚与融合能力&#xff0c;在安防监控领域展现出了巨大的应用潜力和价值。本文将详细介绍EasyCVR视…

权限束缚术:windows工具自动化权限提升

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理利用工具全自动化提权的相关操作方法 因为我没有相关的环境复现&#xff0c;所以没有成功 不过复现的操作就是下面整理的操作 溢出漏洞提权原理 利用溢出漏洞提权&#xff0c;实际上就是一次判断过往的…

极简聊天室-websocket版

再写一个极简聊天室的websocket版&#xff0c;在本例中&#xff0c;websocket仅用于服务器向客户端传输信息&#xff0c;客户端向服务器发送信息是传统的http post方式&#xff0c;用axios来实现的&#xff0c;当然websocket本身是支持双向通信&#xff0c;主要是为了方便跟前面…

Selenium 无法定位元素的几种解决方案

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 1、frame/iframe表单嵌套 WebDriver只能在一个页面上对元素识别与定位&#xff0c;对于frame/iframe表单内嵌的页面元素无法直接定位。 解决方法&#xff1a; d…

LLM大模型实战项目--基于ChatGLM2的小书虫文档阅读助手

本文介绍如此从零开始编写一个基于ChatGLM2的文档阅读助手 一、项目介绍 二、获取API接口 三、环境配置 四、代码实现 五、效果展示 一、项目介绍 小书虫&#x1f4da; 文档阅读助手是一个基于百度千帆大模型平台的Web应用程序&#xff0c;核心是清华大学训练的ChatGLM2大模…

算法加项目

1.仅加号 很简单&#xff0c;找到每次添加后最小的即可&#xff0c;这里不做演示。 2.采药 dp&#xff0c;for1数目&#xff0c;for2时间&#xff0c;简单的dp模板题目。 #include<bits/stdc.h> using namespace std; int n,m; const int N105,M105; long long a[M],b[M…

TInyWebServer面试题

一、项目介绍 &#xff08;1&#xff09;为什么要做这样一个项目&#xff1f; &#xff08;2&#xff09;介绍一下你的项目 这个项⽬是我在学习计算机⽹络和Linux socket编程过程中独⽴开发的轻量级Web服务器&#xff0c;服务器的⽹络模型是主从reactor加线程池的模式&#xf…

VMware虚拟机网络模式配置详解【原理,功能,特点层面】

VMware虚拟机网络模式配置详解【原理,功能,特点层面】 文章目录 VMware虚拟机网络模式配置详解【原理,功能,特点层面】桥接模式&#xff08;Bridged&#xff09;原理功能点介绍虚拟网络编辑器配置虚拟机配置 配置教程编辑-虚拟网络编辑器虚拟机网络配置 特点 NAT模式概念功能点…