堆的概念与实现

目录

一、堆的介绍

1.堆的概念

2.堆的性质:

3.堆的结构

 二、堆的实现

1.堆的定义

2.接口函数

三、堆的实现

 1.堆的初始化

2.堆的销毁

 3.获取堆顶数据

4.判断堆是否为空

5. 堆的插入

 向上调整算法(重点)

向下调整算法(重点)

6.删除堆顶元素

7.堆的大小

 四、完整代码

heap.h

heap.c 


 

一、堆的介绍

1.堆的概念


堆:如果有一个关键码的集合K={k0,k1,k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足ki<=k2i+1且ki<=k2i+2(或满足ki>=k2i+1且ki>=k2i+2),其中i=0,1,2,…,则称该集合为堆。
小堆:将根结点最小的堆叫做小堆,也叫最小堆或小根堆。
大堆:将根结点最大的堆叫做大堆,也叫最大堆或大根堆。

2.堆的性质:


 堆中某个结点的值总是不大于或不小于其父结点的值。
 堆总是一棵完全二叉树。

3.堆的结构

 二、堆的实现

1.堆的定义

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

注:这里实现的是数组堆 

2.接口函数

 

void HeapInit(HP* php);
void HeapDestroy(HP* php);
//插入x继续保持堆形态
void HeapPush(HP* php, HPDataType x);
//删除堆顶元素
void HeapPop(HP* php);
HeapTop(HP* php);
//返回堆顶元素
HPDataType HeapTop(HP* php);
//判空
bool HeapEmpty(HP* php);
//堆的大小
int HeapSize(HP* php);
//向下调整
void AdjustDown(HPDataType* a, int n, int parent);
//向上调整
void AdjustUp(HPDataType* a, int child);
void Swap(HPDataType* p1, HPDataType* p2);

三、堆的实现

 1.堆的初始化

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

2.堆的销毁

void HeapDestroy(HP* php)
{free(php->a);free(php);php = NULL;
}

 3.获取堆顶数据

//返回堆顶元素
HPDataType HeapTop(HP* php)
{assert(php);return php->a[0];
}

4.判断堆是否为空

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

5. 堆的插入

插入的核心思路

① 先将元素插入到堆的末尾,即最后一个孩子之后。

② 插入之后如果堆的性质遭到破坏,就将新插入的节点顺着其的父亲往上调整到合适位置。直到调到符合堆的性质为止。

根据堆的性质,如果不满足大堆和小堆,出现子大于父或父大于子的情况,为了保证插入之后堆还是堆,我们就需要进行自下往上的调整。堆插入数据对其他节点没有影响,只是可能会影响从它到根节点路径上节点的关系。

 向上调整算法(重点)

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

 父亲的下标=(孩子的下标-1)/2,知道了这个,就很好操作了,最坏的情况就是要调到根的位置,即parent=child,这里之所以是chile>0,而不是parent<0,是因为当child=0时,parent依然等于0,不可能小于0的。

向下调整算法(重点)

 现在我们给出一个数组,逻辑上看作一棵完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆

 

向下调整算法的基本思想(小堆):
 1.从根结点处开始,选出左右孩子中值较小的孩子。
 2.让小的孩子与其父亲进行比较。
 若小的孩子比父亲还小,则该孩子与其父亲的位置进行交换。并将原来小的孩子的位置当成父亲继续向下进行调整,直到调整到叶子结点为止。
 若小的孩子比父亲大,则不需处理了,调整完成,整个树已经是小堆了。

 我们首先定义一个minChild,这个是左孩子和右孩子中较小的孩子,parent和它进行交换。

这里调整中有两个结束条件,第一个是父亲小于孩子就停止,第二个是调整到叶子节点了,也就是minChild>n就调整完毕。

void AdjustDown(HPDataType* a, int n, int parent)
{int minChild = parent * 2 + 1;while (minChild < n){if ((minChild+1)<n&&a[minChild] > a[minChild + 1]){minChild++;}if (a[parent] > a[minChild]){Swap(&a[parent], &a[minChild]);parent = minChild;minChild = parent * 2 + 1;}else{break;}}}

使用堆的向下调整算法,最坏的情况下(即一直需要交换结点),需要循环的次数为:h - 1次(h为树的高度)。而h = (N为树的总结点数)。所以堆的向下调整算法的时间复杂度为:O(logN) 。 

6.删除堆顶元素

//删除堆顶元素 -- 找次打或者次小
void HeapPop(HP* php)
{ assert(php);assert(!HeapEmpty(php));Swap(&(php->a[0]),&(php->a[php->size-1]) );php->size--;AdjustDown(php->a, php->size, 0);
}

直接删除堆顶元素,会破坏堆的结构,所以这里我们让堆顶元素和最后一个元素进行交换,然后size--,重新向下调整,构建堆。 

7.堆的大小

int HeapSize(HP* php)
{return php->size;
}


 四、完整代码

heap.h

#define  _CRT_SECURE_NO_WARNINGS
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}HP;void HeapInit(HP* php);
void HeapDestroy(HP* php);
//插入x继续保持堆形态
void HeapPush(HP* php, HPDataType x);
//删除堆顶元素
void HeapPop(HP* php);
HeapTop(HP* php);
//返回堆顶元素
HPDataType HeapTop(HP* php);
//判空
bool HeapEmpty(HP* php);
//堆的大小
int HeapSize(HP* php);
//向下调整
void AdjustDown(HPDataType* a, int n, int parent);
//向上调整
void AdjustUp(HPDataType* a, int child);
void Swap(HPDataType* p1, HPDataType* p2);

heap.c 

#define  _CRT_SECURE_NO_WARNINGS
#define  _CRT_SECURE_NO_WARNINGS
#include "heap.h"void HeapPrint(HP* php)
{for (int i = 0; i < php->size; ++i){printf("%d ", php->a[i]);}printf("\n");
}void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = php->capacity = 0;
}
void HeapDestroy(HP* php)
{free(php->a);free(php);php = NULL;
}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;}}
}void AdjustDown(HPDataType* a, int n, int parent)
{int minChild = parent * 2 + 1;while (minChild < n){if ((minChild+1)<n&&a[minChild] > a[minChild + 1]){minChild++;}if (a[parent] > a[minChild]){Swap(&a[parent], &a[minChild]);parent = minChild;minChild = parent * 2 + 1;}else{break;}}}//插入x继续保持堆形态
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,sizeof(HPDataType)*newcapacity);if (tmp == NULL){perror("realloc fail");exit(-1);}php->a = tmp;php->capacity = newcapacity;}php->a[php->size] = x;php->size++;//向上调整AdjustUp(php->a, php->size - 1);}
//删除堆顶元素 -- 找次打或者次小
void HeapPop(HP* php)
{ assert(php);assert(!HeapEmpty(php));Swap(&(php->a[0]),&(php->a[php->size-1]) );php->size--;AdjustDown(php->a, php->size, 0);
}
//返回堆顶元素
HPDataType HeapTop(HP* php)
{assert(php);return php->a[0];
}
bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}
int HeapSize(HP* php)
{return php->size;
}

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

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

相关文章

【unity小技巧】unity 把window项目打包成只有一个exe的运行文件

文章目录 前言一、unity游戏打包window二、下载安装WinRAR压缩包打包工具三、添加压缩文件1、选择全部6个&#xff08;5个也可以&#xff0c;这个64.exe文件可以省略&#xff09;文件&#xff0c;右键点击添加到压缩文件2、修改压缩文件名&#xff0c;后缀改成.exe3、选择高级–…

【MySQL】索引和事物

索引和事物 索引索引是什么索引的基本操作索引部分原理数据结构讨论B-树B树 MySQL的索引实现 事物事物的概念事物的使用事物的四大特性(ACID)事物并发问题事物的隔离级别 索引 索引是什么 在正常情况下, 数据库去搜索数据, 都是通过一行行的遍历, 然后找到符合要求的行并且筛…

sql中索引查看是否生效

在pg数据库中有多种索引存在&#xff0c;在一般情况下我们取使用普通索引 以下是一些常见导致索引未命中的原因和优化策略 1.如果查询中的条件与索引字段的顺序不匹配&#xff0c;或者索引字段没有完全包含在查询条件中&#xff0c;索引可能不会被使用。 2.在查询中使用函数…

golang学习笔记05——golang协程池,怎么实现协程池?

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang实战大纲golang优秀开发常用开源库汇总golang学习笔记01——基本数据类型golang学习笔记02——gin框架及基本原理golang学习笔记03——gin框架的核心数据结构golang学习笔记04——如何真正写好Golang代码&#xff1f…

从卫星和飞机等不同传感器方面由QGIS 遥感分析

在地理信息科学 (GIS) 中,遥感是指从远处获取有关地球表面特征信息的行为。遥感数据是从许多不同的平台获取而来,包括卫星、飞机和具有许多不同传感器的固定仪器,包括光谱图像(相机)和激光雷达。最常见的遥感数据形式是卫星和航空图像。 为了充分实现这些照片的价值,需要…

C++类型转换,特殊类设计,IO流

1.类型转换 什么是类型转换&#xff1f;我们知道有些数字类型可以相互转换&#xff0c;如double类型可以转换为int类型&#xff0c;这样的转换会发生切割将double类型的小数部分切割掉丢失精度&#xff1b;还有在前面的多态那块有一个虚函数指针表&#xff0c;这个虚函数指针表…

ZYNQ 入门笔记(二):动态时钟

文章目录 1 概述1.1 DRP1.2 AXI4-Lite 2 示例2.1 单时钟输出2.2 多时钟输出 3 参考文档 1 概述 Clocking Wizard 可通过配置内部寄存器动态调整输出频率&#xff0c;配置接口可选 DRP 或 AXI4-Lite&#xff0c;其中 AXI4-Lite 实际上是对 DRP 接口的封装 1.1 DRP 通过 DRP 接…

用RNN(循环神经网络)预测股票价格

RNN&#xff08;循环神经网络&#xff09;是一种特殊类型的神经网络&#xff0c;它能够处理序列数据&#xff0c;并且具有记忆先前信息的能力。这种网络结构特别适合于处理时间序列数据、文本、语音等具有时间依赖性的问题。RNN的核心特点是它可以捕捉时间序列中的长期依赖关系…

C2免杀--手工shellcode编译,shellcode免杀思路

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要整理C2免杀中 shellcode代码免杀的相关部分 shellcode概念 我们也不啰嗦&#xff0c;我直接直观的描述一下他。 他就是一串机器能运行的代码&#xff0c;但是他不是正统的python&#xff0c;c&#xff…

中伟视界:煤矿皮带运输机异物监测AI算法能检测哪几种异物,通过什么方式来判断异物?

在矿山运输系统中&#xff0c;运输皮带上可能出现各种异物&#xff0c;如大煤块、锚杆、钻杆、煤矸石、木板、铁棍等。这些异物会对运输系统造成损害&#xff0c;影响生产效率&#xff0c;甚至引发安全事故。为了实时监测并识别这些异物&#xff0c;现代技术采用AI算法进行分析…

QT串口读取Serial->readAll()踩过的坑

QT串口读取Serial->readAll接收不完全踩过的坑 Chapter1 QT串口读取Serial->readAll()踩过的坑坑一&#xff1a;坑二 Chapter2 [QT串口上位机BUG解决]json解析数据bug以及接收数据问题问题描述原因分析&#xff1a;解决方案&#xff1a;一、是数据采集端&#xff08;单片…

Go语言?IDEA能支持吗?增删查走起?

序&#xff1a; 最近突然身边突然开始冒出关于go语言的只言片语&#xff0c;很好奇这个go语言是怎么样的&#xff1f;这几天有空就会去网上浏览一遍各位大咖的简介。这边主要是已学习为目的&#xff0c;关键人家都说它好这边记录一下学习过程的进坑和爬坑过程供大家娱乐一下。…

OpenCV结构分析与形状描述符(8)点集凸包计算函数convexHull()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 查找一个点集的凸包。 函数 cv::convexHull 使用斯克拉斯基算法&#xff08;Sklansky’s algorithm&#xff09;来查找一个二维点集的凸包&#…

视频回放 | DolphinDB 2024 年度峰会主会场演讲精彩回顾

9 月 6 日&#xff0c;“以实时&#xff0c;见未来” DolphinDB 2024 年度峰会在杭州成功举办。上午&#xff0c;DolphinDB 创始团队与技术团队分别从不同方面介绍了 DolphinDB 这一年来的创新和突破。没来到现场没关系&#xff0c;现在就为您送上全场完整视频回放~&#xff08…

Pyspark下操作dataframe方法(1)

文章目录 Pyspark dataframe创建DataFrame使用Row对象使用元组与scheam使用字典与scheam注意 agg 聚合操作alias 设置别名字段设置别名设置dataframe别名 cache 缓存checkpoint RDD持久化到外部存储coalesce 设置dataframe分区数量collect 拉取数据columns 获取dataframe列 Pys…

CnCrypt(磁盘加密工具绿色版是一款功能强大磁盘加密工具,供大家学习研究参考

CnCrypt(磁盘加密工具)特点 加密单个分区或整个硬盘,所有加密都是以分区为基础的 提供两级方案,以应对被强迫说出密码的情况(如抢劫。隐藏分区(覆盖式密码术,steganography)无法探测到CnCrypt 加密分区(加密数据会被认为是随机数据)。 CnCrypt(磁盘加密工具)特色 1、加密U…

ucx 编译安装检验方式备忘

1&#xff0c; 下载配置编译 预备依赖&#xff1a; sudo apt-get install valgrind sudo apt-get install libibverbs-dev librdmacm-dev 1.1 下载源码 git clone --recursive https://github.com/openucx/ucx.git cd ucx/ git checkout v1.16.0 git 下来的代码&#xff0c;…

《Diffusion Models Without Attention》CVPR2024

摘要 这篇论文探讨了在高保真图像生成领域&#xff0c;去噪扩散概率模型&#xff08;Denoising Diffusion Probabilistic Models, DDPMs&#xff09;的重要性。尽管DDPMs在捕捉复杂视觉分布方面表现出色&#xff0c;但在高分辨率图像生成上面临显著的计算挑战。现有的方法&…

Vue邮件发送:如何有效集成邮件发送功能?

vue邮件发送功能实现方法&#xff1f;Vue邮件发送性能怎么优化&#xff1f; 无论是用户注册验证、密码重置&#xff0c;还是通知提醒&#xff0c;邮件发送功能都能提供重要的支持。本文将详细探讨如何在Vue项目中有效集成邮件发送功能&#xff0c;确保邮件能够准确、及时地送达…

macos 系统文件操作时提示 Operation not permitted 异常解决方法 , 通过恢复模式 开启 /关闭 SIP方法

在macos系统中操作系统文件时提示 Operation not permitted 这个异常, 原因是因为在macos 10.11以上版本中默认启用了 SIP( System Integrity Protection )机制对系统文件进行保护, 要解决这个问题我们需要关机, 然后进入mac的恢复模式 : 在按电源键开机的同时, 一直按住 co…