堆概念和结构

1. 二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中通常 把堆使用顺序结构的数组来存储 ,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构(完全二叉树),一个是操作系统中管理内存区域分段。

顺序存储

2. 堆的概念

堆是将数组数据看作一颗完全二叉树。递增递减数组一定是堆,堆不一定是递增递减数组。在实际意义中,堆可以实现堆排序,时间复杂度是 O(N*longN) ,提高查找效率,解决top k问题。

堆的性质:

1)堆总是一棵完全二叉树

2)堆中某个节点的值总是不大于或不小于其父节点的值

3. 堆的分类

堆可以分为大堆和小堆:

大堆要求: 任意一个父亲 <= 孩子

小堆要求: 任意一个父亲 >= 孩子

堆

4. 堆的实现(数组小堆)

这里将着重利用父子节点之间的关系完成堆的构建以及各类接口的实现:

leftchild = parent*2+1	# 奇数
rightchild = parent*2+2	# 偶数
parent = (child-1)/2	# 不区分左右孩子

如果要实现大堆,就将对应的向下调整算法和向上调整算法的判定更改即可实现。下面将其分为3个模块进行实现小堆Heap.h,Heap.c,test.c

4.1 接口设计(Heap.h)

堆的结构设计和顺序表类似,这里将采用小堆进行设计接口,对堆插入数据时,就要按照堆的规则进行构建。需要注意的是,堆的删除是删除跟节点数据。

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HeapInit(HP* php);
void HeapDestory(HP* php);
// 小堆
// 插入,时间复杂度是O(logN)
void HeapPush(HP* php, HPDataType x);
// 规定删除堆顶,即根节点
// 挪动数据覆盖删除跟会出问题
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
size_t HeapSize(HP* php);
bool HeapEmpty(HP* php);

4.2 接口实现(Heap.c)

1)初始化销毁

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

2)插入,时间复杂度是O(logN)

因为扩容操作只有 HeapPush 使用,因此不将其作为单独函数。

插入的过程中要保证堆符合大堆或者小堆的规则,因此,要对其进行调整,这里将引入向上调整算法,并将其作为单独函数。

向上调整算法主要利用父子下标的特性, 在数据插入成为叶子时,将其与父节点比较,直到满足堆的规则 (这里小堆要满足父节点小于等于子节点 )

插入

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;}}
}// 插入,时间复杂度是O(logN)
void HeapPush(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\n");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}

因为后续要重复进行交换,所以将其作为单独一个函数

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

3)删除,规定删除堆顶,即根节点

删除是删头,可以选出最大最小的数据,尾删没有多大意义。

有人会想到挪动数据覆盖删除根节点,但会出问题,而且数组不一定有序,挪动后整棵树的父子关系就会全乱了,并且也可能就不是堆了。

因此,这里采用的办法是首先进行首尾交换,然后尾删,这样左右子树依旧是小堆,然后再用向下调整算法,从而将堆构建完成。

删除

void AdjustDown(HPDataType* a, int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (child + 1 < size && 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 HeapPop(HP* php)
{assert(php);// 空assert(php->size > 0);Swap(&php->a[0], &php->a[php->size - 1]);// 不需要进行覆盖php->size--;AdjustDown(php->a, php->size, 0);
}

4)堆顶数据、堆大小、堆空

这三个操作就相对简单,返回堆顶元素要检查堆是否为空。

HPDataType HeapTop(HP* php)
{assert(php);// 空assert(php->size > 0);return php->a[0];
}size_t HeapSize(HP* php)
{assert(php);return php->size;
}bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

4.3 完整代码

Heap.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>typedef int HPDataType;typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HeapInit(HP* php);
void HeapDestory(HP* php);
// 小堆
// 插入,时间复杂度是O(logN)
void HeapPush(HP* php, HPDataType x);
// 规定删除堆顶,即根节点
// 挪动数据覆盖删除跟会出问题
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
size_t HeapSize(HP* php);
bool HeapEmpty(HP* php);

Heap.c

#include "Heap.h"// 初始化销毁
void HeapInit(HP* php)
{assert(php);php->a = NULL;php->capacity = php->size = 0;
}void HeapDestory(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}// 实现小堆
void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}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;}}
}// 插入,时间复杂度是O(logN)
void HeapPush(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\n");exit(-1);}php->a = tmp;php->capacity = newCapacity;}php->a[php->size] = x;php->size++;AdjustUp(php->a, php->size - 1);
}// 规定删除堆顶,即根节点
// 挪动数据覆盖删除跟会出问题
void AdjustDown(HPDataType* a, int size, int parent)
{int child = parent * 2 + 1;while (child < size){if (child + 1 < size && 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 HeapPop(HP* php)
{assert(php);// 空assert(php->size > 0);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}HPDataType HeapTop(HP* php)
{assert(php);// 空assert(php->size > 0);return php->a[0];
}size_t HeapSize(HP* php)
{assert(php);return php->size;
}bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

test.c

#include "Heap.h"int main()
{int a[] = { 2,7,0,21,56,786,1,3 };HP hp;HeapInit(&hp);for (int i = 0; i < sizeof(a) / sizeof(int); i++){HeapPush(&hp, a[i]);}int k = 7;printf("打印小堆顶前7个数据:\n");while (k--){printf("%d ", HeapTop(&hp));HeapPop(&hp);}printf("\n堆大小为:%d, 堆是否为空:%d\n", HeapSize(&hp), HeapEmpty(&hp));printf("销毁小堆!\n");HeapDestory(&hp);return 0;
}

运行效果

运行效果
在学会堆的知识后,我们应该怎么应用呢?
下面将介绍两个使用的堆使用:
堆排序&TopK问题:堆的实际应用:堆排序&TopK问题

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

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

相关文章

VUE的脚手架搭建引入类库

VUE的小白脚手架搭建 真的好久好久自己没有发布自己博客了,对于一直在做后端开发的我 ,由于社会卷啊卷只好学习下怎么搭建前端,一起学习成长吧~哈哈哈(最终目的,能够懂并简易开发) 文章目录 VUE的小白脚手架搭建1.下载node.js2.安装vue脚手架3.创建一个项目4.代码规范约束配置(…

使用 Arduino 和 ThingSpeak 通过互联网进行实时温度和湿度监测

使用 ThingSpeak 和 Arduino 通过 Internet 进行温度和湿度监控 湿度和温度是许多地方(如农场、温室、医疗、工业家庭和办公室)非常常见的测量参数。我们已经介绍了使用 Arduino 进行湿度和温度测量,并在 LCD 上显示数据。 在这个物联网项目中,我们将使用ThingSpeak在互联…

论文分享:PL-ALF框架实现无人机低纹理环境自主飞行

在室内仓库、地下隧道等低纹理复杂场景中&#xff0c;无人机依赖视觉传感器进行自主飞行时&#xff0c;往往会遇到定位精度低、路径规划不稳定等难题。针对这一问题&#xff0c;重庆邮电大学计算机学院雷大江教授团队在IEEE Trans期刊上提出了一种新型自主飞行框架&#xff1a;…

[Java实战]性能优化qps从1万到3万

一、问题背景 ​ 事情起因是项目上springboot项目提供的tps达不到客户要求,除了增加服务器提高tps之外,作为团队的技术总监,架构师,技术扛把子,本着我不入地狱谁入地狱的原则,决心从代码上优化,让客户享受到飞一般的感觉。虽然大多数编程工作在写下第一行代码时已经完成…

如何筛选能实现共享自助健身房“灵活性”的物联网框架?

共享自助健身房已经成为一种新兴的健身方式&#xff0c;这种模式方便快捷&#xff0c;尤其适合i人健身爱好者&#xff0c;市场接受度还是挺好的。对于无人自助式的健身房要想实现灵活性&#xff0c;要挑选什么样的物联网框架呢&#xff1f; 1. 支持多种通信协议 共享自助健身…

【后端】【django】抛弃 Django 自带用户管理后,能否使用 `simple-jwt`?

抛弃 Django 自带用户管理后&#xff0c;能否使用 simple-jwt&#xff1f; 一、结论 是的&#xff0c;即使抛弃了 Django 自带的用户管理&#xff08;AbstractUser 或 AbstractBaseUser&#xff09;&#xff0c;仍然可以使用 django-rest-framework-simplejwt&#xff08;简称…

【量化科普】Correlation,相关性

【量化科普】Correlation&#xff0c;相关性 &#x1f680;量化软件开通 &#x1f680;量化实战教程 在量化投资领域&#xff0c;相关性&#xff08;Correlation&#xff09;是一个核心概念&#xff0c;用于衡量两个变量之间的线性关系强度和方向。简单来说&#xff0c;它告…

大数据学习(68)- Flink和Spark Streaming

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…

MCU详解:嵌入式系统的“智慧之心”

在现代电子设备中&#xff0c; MCU&#xff08;Microcontroller Unit&#xff0c;微控制器&#xff09;扮演着至关重要的角色。从智能家居到工业控制&#xff0c;从汽车电子到医疗设备&#xff0c;MCU以其小巧、低功耗和高集成度的特点&#xff0c;成为嵌入式系统的核心组件。 …

(链表)24. 两两交换链表中的节点

给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2,1,4…

吴恩达机器学习笔记复盘(三)Jupyter NoteBook

Jupyter NoteBook Jupyter是一个开源的交互式计算环境&#xff1a; 特点 交互式编程&#xff1a;支持以单元格为单位编写和运行代码&#xff0c;用户可以实时看到代码的执行结果&#xff0c;便于逐步调试和理解代码逻辑。多语言支持&#xff1a;不仅支持Python&#xff0c;还…

【Linux】从互斥原理到C++ RAII封装实践

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

微服务无状态服务设计

微服务无状态服务设计是构建高可用、高扩展性系统的核心方法。 一、核心设计原则 请求独立性 每个请求必须携带完整的上下文信息&#xff0c;服务不依赖本地存储的会话或用户数据。例如用户认证通过JWT传递所有必要信息&#xff0c;而非依赖服务端Session。 状态外置化 将会话…

30、map 和 unordered_map的区别和实现机制【高频】

底层结构 map底层是红黑树结构&#xff0c;而unordered_map底层是哈希结构; 有序性 但是红黑树其实是一种二叉搜索树&#xff0c;插入删除时会自动排序hash因为是把数据映射到数组上的&#xff0c;而且存在哈希冲突&#xff0c;所以不能保证有序存储 所以有序存储使用map&a…

大数据-spark3.5安装部署之local模式

spark&#xff0c;一个数据处理框架和计算引擎。 下载 local模式即本地模式&#xff0c;就是不需要任何其他节点资源就可以在本地执行spark代码的环境。用于练习演示。 上传解压 使用PortX将文件上传至/opt 进入/opt目录&#xff0c;创建目录module&#xff0c;解压文件至/o…

Manus “Less structure,More intelligence ”独行云端处理器

根据市场调研机构Statista数据显示&#xff0c;全球的AR/AR的市场规模预计目前将达到2500亿美元&#xff0c;Manus作为VR手套领域的领军企业&#xff0c;足以颠覆你的认知。本篇文章将带你解读Manus产品&#xff0c;针对用户提出的种种问题&#xff0c;Manus又将如何解决且让使…

Oracle数据库存储结构--逻辑存储结构

数据库存储结构&#xff1a;分为物理存储结构和逻辑存储结构。 物理存储结构&#xff1a;操作系统层面如何组织和管理数据 逻辑存储结构&#xff1a;Oracle数据库内部数据组织和管理数据&#xff0c;数据库管理系统层面如何组织和管理数据 Oracle逻辑存储结构 数据库的逻…

芯驿电子 ALINX 亮相德国纽伦堡,Embedded World 2025 精彩回顾

2025年3月13日&#xff0c;全球规模最大的嵌入式行业盛会——德国纽伦堡国际嵌入式展&#xff08;embedded world 2025&#xff09;圆满落幕。 在这场汇聚全球 950 家展商、3 万余专业观众的科技盛宴中&#xff0c;芯驿电子 ALINX 展位人头攒动&#xff0c;多款尖端产品吸引客户…

Nexus File类型Blob Stores迁移至Minio操作指南(上)

#作者&#xff1a;闫乾苓 文章目录 目的前期准备查看file类型Blob Stores数据目录位置aws cli客户端连接工具OrientDB cli客户端连接工具在minio中新建 bucket 目的 增强nexus构件数据的高可用性和扩展性 前期准备 查看并记录需要迁移的Blob Store及repository 查看fil…

蓝桥杯嵌入式组第十二届省赛题目解析+STM32G431RBT6实现源码

文章目录 1.题目解析1.1 分而治之&#xff0c;藕断丝连1.2 模块化思维导图1.3 模块解析1.3.1 KEY模块1.3.2 LED模块1.3.3 LCD模块1.3.4 TIM模块1.3.5 UART模块1.3.5.1 uart数据解析 2.源码3.第十二届题目 前言&#xff1a;STM32G431RBT6实现嵌入式组第十二届题目解析源码&#…