堆详解以及简单的堆排序(源代码)

news2024/10/6 22:29:46

一、什么是堆?

堆是将数组看作一颗完全二叉树

大堆:任意一个父亲大于等于孩子

小堆:任意一个父亲小于等于孩子

有序数组一定是堆
但是堆不一定有序

注意:此“堆”是一个数据结构,用来表示完全二叉树
还有另外一个“堆”,是内存区域的划分,是我们动态申请内存的内存区域,属于操作系统的概念
属于不同学科中的同名概念而已

二、堆的应用场景


1、堆排序,O(N*logN)(在一堆数据中找到某个数据)
2、top K问题(一堆数据中找到前K个最大或者最小的数据)


堆二叉树插入值:向上调整,和其祖先进行比较

数组可以建立堆的核心是,利用完全二叉树的父子和左右孩子下标的关系特点
同时,在实际的物理存储中是数组,但是想象中,我们处理的是逻辑结构中的完全二叉树    

堆的删除默认是删除堆顶
向下调整算法:删除堆顶元素,数组尾和堆顶元素交换,删除尾巴,然后交换过去的堆顶又向下调整(这里要注意数组越界的问题)

fscanf:将数据流(一般是从文件中读取,就是文件指针)中的数据放到对应格式的位置上去
fscanf(文件指针,格式%d,写入的位置&x);

fprintf();写文件

(free就算传入的是空,也没有问题,因为free对空进行了检查)

正数数据类型:size_t

调试:结构体内部情况struct.a,8(这个8代表的是a中的8个数据值)

三、堆的基本操作源代码

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* _a;
	int _size;
	int _capacity;
}Heap;
//交换函数
void Swap(HPDataType* a, HPDataType* b);

//向下调整
void AdujustDown(HPDataType* a, int size,int parent);

//向上调整
void AdujustUp( HPDataType* a, int child);

//初始化堆
void HeapInit(Heap* hp);

// 堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);
//堆排序
void HeapSort(int* a, int n);

#include"Heap.h"
//大堆

//初始化堆
void HeapInit(Heap* hp)
{
	assert(hp);
	hp->_a = NULL;
	hp->_capacity = hp->_size = 0;
}

void Swap(HPDataType* a, HPDataType*b)
{
	HPDataType tmp = *a;
	*a = *b;
	*b = tmp;
}

//向下调整
void AdujustDown(HPDataType* a, int size, int parent)
{
	//假设左孩子比较大
	int child = parent * 2 + 1;
	while(child < size)
	{
		if (child + 1 < size && a[child + 1] > a[child])
		{
			//更改比较大孩子
			++child;
		}
		if (a[parent] < a[child])
		{
			Swap(&a[parent],&a[child]);
			parent = child;//更新父节点
			child = parent * +1;//依旧将孩子更新为左孩子
		}
		else
		{
			break;
		}
	}
}

//向上调整
void AdujustUp(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 = (parent - 1) / 2;
		}
		else
		{
			break;
		}

	}
}


// 堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n)
{
	assert(hp);
	HPDataType* tmp = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (tmp ==NULL)
	{
		perror("malloc fail");
		exit(-1);
		hp->_a = tmp;
		hp->_size = n;
		hp->_capacity = n;
	}
	//每插入一个值,就调整一个值	
	for (int i = 0;i<n;++i)
	{
		AdujustUp(a,i);
	}
	for (int i = 0;i<n;++i)
	{
		HeapPush(&hp->_a,a[i]);
	}
}

// 堆的销毁
void HeapDestory(Heap* hp)
{
	assert(hp);
	hp->_a = NULL;
	hp->_capacity = 0;
	hp->_size = 0;
	printf("Destory Succeed\n");
}
// 堆的插入
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 (tmp == NULL)
		{
			perror("realloc fail ");
			exit(-1);
		}
		hp->_a = tmp;
		hp->_capacity = newCapacity;
	}
	hp->_a[hp->_size] = x;
	hp->_size++;
	
	//插入后向上调整
	AdujustUp(hp->_a,hp->_size - 1);
}

// 堆的删除
void HeapPop(Heap* hp)
{
	assert(hp);
	assert(hp->_size > 0);

	//先交换,再向下调整
	Swap(&hp->_a[0],&hp->_a[hp->_size - 1]);
	hp->_size--;
	AdujustDown(hp->_a,hp->_size,0);
}

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

//交换数据,对剩下的数据进行向调整
void HeapSort(int* a, int n)
{
	//for (int i = 0;i<n;++i)
	//{
	//	AdujustUp(a,i);
	//}
	// O(N)
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdujustDown(a, n, i);
	}

	while(n>0)
	{
		Swap(&a[n - 1], &a[0]);
		AdujustDown(a, n-1, 0);
		n--;
	}

	
}

#include"Heap.h"

int main()
{
	int a[] = { 0,3,5,7,2,9,4,4,6 };
	int n = sizeof(a) / sizeof(int);
	HeapSort(&a,n);
	 
	for (int i = 0; i < n; ++i)
	{
		printf("%d ",a[i]);
	}
	return 0;
}

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

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

相关文章

渗透某巨型企业某个系统的奇葩姿势

本文由掌控安全学院 - urfyyyy 投稿 前言 这个月都在做一个巨型合作企业的渗透测试&#xff0c;这个系统本无方式getshell&#xff0c;得亏我心够细&#xff0c;想的多&#xff0c;姿势够骚。 文中重码&#xff0c;且漏洞已修复。 过程 找到getshell点 目标系统功能很少&…

Python实现时间序列分析霍尔特季节性平滑模型(Holt算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 霍尔特季节性平滑模型是指数平滑技术的一种扩展形式&#xff0c;由E. S. Holt和P. R. Winters分别独立…

nginx-在应用程序中发现不必要的Http响应头

描述:一般是在返回的响应表头中出现了Server键值对 解决方案: 通过headers-more-nginx-module模块将Server去除 https://github.com/openresty/headers-more-nginx-module ./configure --add-module/usr/local/headers-more-nginx-modulemakemake install 编译完成后&#…

Maven高级(一)

文章目录 Maven高级&#xff08;一&#xff09;1. 分模块设计与开发1.1 介绍1.2 实践1.2.1 分析1.2.2 实现 1.3 总结 2. 继承与聚合2.1 继承2.1.1 继承关系2.1.1.1 思路分析2.1.1.2 实现 2.1.2 版本锁定2.1.2.1 场景2.1.2.2 介绍2.1.2.3 实现2.1.2.4 属性配置 2.2 聚合2.2.1 介…

window10 远程桌面

1、设置需要被远程的电脑设置不走 设置电脑名字 开始–>设置–>系统–>关于–>系统设置–>重命名计算机名称 设置远程&#xff0c;这一步很重要。你可以选择指定用户来进行远程桌面。通过“高级–》立即查找”可以找到自己想要设置的用户&#xff0c;此处“名…

ERP定制+跨境电商:双剑合璧,打造全球商业帝国

在当今全球化的商业环境下&#xff0c;跨境电商已成为许多企业拓展市场、实现增长的重要途径。然而&#xff0c;要成功经营跨境电商业务&#xff0c;企业需要面对诸多挑战&#xff0c;如跨国物流、支付结算、客户服务等方面的复杂问题。而ERP定制则能为跨境电商提供强大的支持&…

碳化硅模块使用烧结银双面散热DSC封装的优势与实现方法

碳化硅模块使用烧结银双面散热DSC封装的优势与实现方法 新能源车的大多数最先进 (SOTA) 电动汽车的牵引逆变器体积功率密度范围从基于 SSC-IGBT 的逆变器的 <10 kW/L 到基于 SSC-SiC 的逆变器的约 25 kW/L。100 kW/L 代表了这一关键指标的巨大飞跃。 当然&#xff0c;随着新…

每日汇评:黄金有望在复苏之路上重新夺回关键的2025美元关口

周一&#xff0c;金价在本周初延续了其复苏模式&#xff1b; 随着投资者重新评估美联储降息押注&#xff0c;美元跟随美债收益率走软&#xff1b; 黄金买家需要突破21日移动均线2025美元,RSI指数稳定在50以下&#xff1b; 随着买家将上周的复苏模式延续到周一&#xff0c;黄金价…

5G网络RedCap

RedCap&#xff1a;RedCap&#xff08;Reduced Capability&#xff09;&#xff0c;即“降低能力”。它是3GPP在5G R17阶段&#xff0c;针对速率、时延要求不高的5G应用场景&#xff0c;专门推出的一种新技术标准协议&#xff0c;旨在全面提升5G网络质量和覆盖率&#xff0c;也…

在Python中捕获finally语句中异常消息

当我们在使用Python时&#xff0c;finally语句用于定义无论是否发生异常都必须执行的代码块。正常情况下&#xff0c;finally语句不会捕获异常&#xff0c;而是在异常处理完成后执行。如果这时候finally语句中发生了异常&#xff0c;它会覆盖之前的异常&#xff0c;并成为最终的…

【递归】:原理、应用与案例解析 ,助你深入理解递归核心思想

递归 1.基础简介 递归在计算机科学中&#xff0c;递归是一种解决计算问题的方法&#xff0c;其中解决方案取决于同一类问题的更小子集 例如 递归遍历环形链表 基本情况&#xff08;Base Case&#xff09;&#xff1a;基本情况是递归函数中最简单的情况&#xff0c;它们通常是递…

代码随想录 Leetcode509. 斐波那契数

题目&#xff1a; 代码&#xff08;首刷自解 2024年2月19日&#xff09;&#xff1a; class Solution { public:int fib(int n) {if (n < 2) return n;/*三个数表示加法算式里的 加数 加数 和*//*初始化*/int leftVal 0;int rightVal 1;int sum 0;for (int i 2; i <…

循环队列|超详细|数据结构学习讲解与笔记

队列元素先进先出队列只允许在线性表的一端进行操作&#xff0c;是一种操作受限的线性表 队列的基本操作 InItQueue(&Q)初始化队列&#xff0c;构造一个空队列 QEmptyQueue(Q)队列判空FullQueue(Q)队列判满EnQueue(&Q , x)入队操作DeQueue(&Q , &x)出队操作G…

数据结构通讲

目录 集合源码详解 一、常见数据结构讲解 1. 线性数据结构 1.1 数组 1.2 队列 1.3 链表 1.3.1 单向链表 1.3.2 双向链表 1.4 栈 2. 非线性数据结构 2.1 树 2.2 二叉树 2.2.1 概念介绍 2.2.2 遍历操作 2.2.3 删除节点 2.2.4 查找局限性 2.2.5 AVL&#xff08; …

应急响应实战笔记02日志分析篇(4)

第4篇:MSSQL日志分析 常见的数据库攻击包括弱口令、SQL注入、提升权限、窃取备份等。对数据库日志进行分析&#xff0c;可以发现攻击行为&#xff0c;进一步还原攻击场景及追溯攻击源。 0x01 MSSQL日志分析 首先&#xff0c;MSSQL数据库应启用日志记录功能&#xff0c;默认配…

Ubuntu系统搭建HadSky论坛并结合内网穿透实现无公网ip远程访问

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

消息队列(Message Queue)

目录 一、概念 二、消息队列使用场景 三、消息队列的两种模式 1.点对点模式 2.发布/订阅模式 四、常用消息队列介绍 1.RabbitMQ 1) 主要特性 2&#xff09;安装需要 3&#xff09;优点 4&#xff09;缺点 2.ActiveMQ 1&#xff09;主要特性 2) 安装需要 3&#xff09;优…

专业140+总分420+南京信息工程大学811信号与系统考研经验南信大电子信息与通信工程,真题,大纲,参考书

今年顺利被南信大电子信息录取&#xff0c;初试420&#xff0c;专业811信号与系统140&#xff08;Jenny老师辅导班上140很多&#xff0c;真是大佬云集&#xff09;&#xff0c;今年应该是南信大电子信息最卷的一年&#xff0c;复试线比往年提高了很多&#xff0c;录取平均分380…

Spring | Spring事务管理

目录&#xff1a; 1.Spring事务管理 “含义”2.Spring事务管理的 三个“核心接口” :2.1 PlatformTransactionManager 接口PlatformTransactionManager接口 (3个“事务操作方法”)PlatformTransactionManager接口的 “实现类” 2.2 TransactionDefinition 接口2.3 TransactionS…

flex布局、grid布局中的justify、align属性

一、grid中justify-content和justify-items的区别&#xff08;align同理&#xff09;&#xff08;flex中的justify-items属性无效&#xff09; justify-content:相对于父级&#xff0c;水平方向将整体进行对齐 justify-items:针对于每个格&#xff0c;将里面的内容进行对齐&a…