首页 > 其他分享 >堆的实现及其应用

堆的实现及其应用

时间:2024-06-14 20:58:53浏览次数:5  
标签:parent 实现 及其 int HPDataType 应用 child php void

堆的概念

        堆是完全二叉树,分为大堆和小堆。大堆:任何一个父亲都大于等于孩子,小堆:任何一个父亲都小于等于孩子。

堆的实现

目录

typedef int HPDataType;

typedef struct Heap
{ 
	HPDataType* a;
	int size;
	int capacity;
}HP;

//交换函数
void Swap(HPDataType* p1, HPDataType* p2);
//堆的初始化和销毁
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);
//向上调整和向下调整
void AdJustUp(HPDataType* a, int child);
void AdJustDown(HPDataType* a, int n, int parent);

1.堆的初始化

void HPInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->size = php->capacity = 0;
}

可以选择在堆的初始化过程直接对空间大小进行赋值,在这里选择不开空间。

2.堆的销毁

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

3.交换函数

void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

4.向上调整

        堆在数组中存储,所以根节点的小标为孩子节点下标减一再除以二,向上调整即将孩子节点向上调整,直到满足要求的大堆(小堆)建成。

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;
		}
	}
}

5.向下调整

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;
		}
	}
	
}

6.堆的插入

void HPPush(HP* php, HPDataType x)
{
	assert(php);
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, newcapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			return;
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}
	php->a[php->size] = x;
	php->size++;

	AdJustUp(php->a, php->size - 1);
}

我们选择在堆插入函数中进行空间的开创。

7.堆数据删除

        对于堆中数据的删除,删除叶子结点数据意义不大,我们主要是要删除顶层节点数据,思路将顶部数据进行调整到最后的叶子结点处,在对其进行删除即可。

void HPPop(HP* php)//向下调整算法,可用于topk问题(找最大(最小)的几个值)
{
	assert(php);
	assert(php->size > 0);
	Swap(&php->a[0], &php->a[php->size - 1]);

	php->size--;
	AdJustDown(php->a, php->size, 0);
}

8.取堆顶数据

        对于只有一条语句的函数,我们为了方便调控,仍进行函数调用。

HPDataType HPTop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	return php->a[0];
}

9.堆的判空

bool HPEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

堆排序

建堆

        通过循环调用向上调整函数,可以将数组调整为堆。代码如下:

void HeapSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		AdJustUp(a, i);
	}
}

        另外,若使用向下调整建堆时间复杂度会更低

排序

升序建大堆

如果升序建小堆,将顶层最小数据取出后,导致后面数据顺序全部混乱,所以我们建大堆。

将最大的数往堆最后位置数据交换,再将其放入新数组的最后一位即可。代码如下:

void HeapSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		AdJustUp(a, i);
	}
	
	int end = n - 1;
	while (end > 0)
	{	
		Swap(&a[0], &a[end]);
		AdJustDown(a, end, 0);
		--end;
	}
}	

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 HeapSort(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		AdJustUp(a, i);
	}
	
	int end = n - 1;
	while (end > 0)
	{	
		Swap(&a[0], &a[end]);
		AdJustDown(a, end, 0);
		--end;
	}
}	

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;
		}
	}
	//向上调整同理
}

如果觉得我写得不错的话,请别忘了点赞收藏加评论!!

标签:parent,实现,及其,int,HPDataType,应用,child,php,void
From: https://blog.csdn.net/Frenemy__/article/details/139657456

相关文章

  • 进程状态及其转换
    0号进程(idle):在linux系统启动的时候最先运行的进程就是0号进程,0号进程又叫空闲进程。如果系统上没有其他进程执行那么0号进程就执行。0号进程是1号进程和2号进程的父进程1号进程(init):init进程是由0号进程创建得到的,它的主要工作是系统的初始化。当初始化工作执行完之后,它......
  • 利用信号量实现线程顺序执行
    线程顺序循环执行的场景在多线程编程中并不罕见,尤其是在需要协调多个线程按特定顺序重复执行任务的情况下。以下是几个常见的例子:生产者-消费者模型:在这种模型中,生产者线程生成数据并将其放入缓冲区,而消费者线程从缓冲区取出数据进行处理。这种情况下,生产者和消费者线程通常按顺......
  • Java数据结构:从基础到高级应用
    Java是一种广泛应用的编程语言,拥有强大的数据结构库,使程序员能够轻松地处理各种数据和算法。本文将深入探讨Java中的数据结构,从基础概念到高级应用,包括示例代码和实际用例。第一部分:基础数据结构1.数组(Array)Java中的数组是一种基本的数据结构,用于存储一组相同类型的元素。......
  • 使用shell脚本在Linux中管理Java应用程序
    目录前言一、目录结构二、脚本实现1.脚本内容2.使用说明2.1配置脚本2.2脚本部署2.3操作你的Java应用总结前言在日常开发和运维工作中,管理基于Java的应用程序是一项基础且频繁的任务。本文将通过一个示例脚本,展示如何利用Shell脚本简化这一流程,实现Java应用的一键式启动、......
  • 前端使用 Konva 实现可视化设计器(15)- 自定义连接点、连接优化
    前面,本示例实现了折线连接线,简述了实现的思路和原理,也已知了一些缺陷。本章将处理一些缺陷的同时,实现支持连接点的自定义,一个节点可以定义多个连接点,最终可以满足类似图元接线的效果。请大家动动小手,给我一个免费的Star吧~大家如果发现了Bug,欢迎来提Issue哟~github源码g......
  • LVS负载均衡集群企业级应用实战-LVS-DR(四)
    目录LVS-DR 一.环境准备二.对虚拟主机操作三.对真实服务器操作 四.打开网页测试LVS-DR 一.环境准备三台虚拟机,都要在同一网段内,统一关闭防火墙和selinux,时间同步,配置好YUM源。系统用centos和roucky都行。主机名主机IP模拟服务器系统用途localhostVIP:1......
  • 【LLM应用】大模型在编写代码中的应用
    随着人工智能技术的飞速发展,大模型在各个领域的应用越来越广泛。在代码编程领域,大模型通过深度学习技术,极大地提高了代码编写的效率、质量和可维护性。大模型在代码编程中的应用代码自动补全与智能提示大模型通过学习大量代码样本,能够预测并推荐接下来要编写的代码片段,实现......
  • 【LLM应用】大模型赋能企业招投标
    一、背景当前,人工智能技术的发展与应用已上升到国家战略高度。步入2024年,大模型进入应用落地的关键时期,大模型赋能千行百业的时代已经到来。人工智能技术的高速发展也将为招标采购行业带来巨大变革。通常,一个完整的招投标流程,大致如下:招标(采购方)=〉投标(供应商)=》开标=〉......
  • SpringBoot集成devtools实现热部署调试
    SpringBoot集成devtools实现热部署调试简述参考多篇网上文章终于实现热部署,中间出现过更改的文件已加载,但是并未自动重启的情况。由于判断不出哪些操作时多余的,记录了所有修改项操作步骤1.pom文件中增加依赖<dependency><groupId>org.springframework.b......
  • 【视频讲解】LSTM神经网络模型在微博中文文本评论情感分析和股市预测应用附代码数据
    全文链接:https://tecdat.cn/?p=36471原文出处:拓端数据部落公众号分析师:ShuaiFung本文将通过视频讲解,展示如何用python的LSTM模型对中文文本评论情感分析,并结合一个TensorFlow的长短期记忆神经网络(LSTM)、指数移动平均法预测股票市场和可视化实例的代码数据,为读者提供一套完整......