数据结构——lesson7二叉树 堆的介绍与实现

前言💞💞

啦啦啦~这里是土土数据结构学习笔记🥳🥳

在这里插入图片描述
💥个人主页:大耳朵土土垚的博客
💥 所属专栏:数据结构学习笔记
💥对于数据结构顺序表链表有疑问的都可以在上面数据结构的专栏进行学习哦~ 欢迎大家🥳🥳点赞✨收藏💖评论哦~🌹🌹🌹 有问题可以写在评论区或者私信我哦~

一、 堆的概念及结构

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

堆的性质

  1. 堆中某个节点的值总是不大于或不小于其父节点的值;
  2. 堆总是一棵完全二叉树。
    在这里插入图片描述

✨✨简单来说大堆指的是父节点都大于子节点的完全二叉树;
小堆指的是父节点都小于子节点的完全二叉树;
大堆的根节点是最大的,小堆是最小的。

二、堆的实现

1.堆的创建

我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。

下面是堆创建以及实现堆所需的函数,后文将一一介绍

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.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);
// 堆的判空
int HeapEmpty(Heap* hp);

2.堆的初始化

void HeapInit(Heap* hp)

//堆的初始化
void HeapInit(Heap* hp)
{assert(hp);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}

3.堆的删除(删除堆顶元素)

void HeapPop(Heap* hp)

在介绍堆的删除之前我们先介绍堆向下调整算法;
显而易见堆的删除不可能像顺序表那样删除尾部元素size–就行,我们需要玩点高深的,删除顶部元素,但删除顶部元素就没办法保证它删除后还是一个堆了,这就要利用我们下面介绍的向下调整算法。

int a[] = {1,8,3,5,7,6}; 

该数组逻辑结构可以看成一个完全二叉树如下图所示:
在这里插入图片描述

我们可以从图中看出它是一颗完全二叉树,但并不是所有的父节点都大于或小于其子节点,所以不是一个堆,接下来我们就可以通过下面介绍的堆向下调整算法将它调整为一个堆。

堆向下调整算法
现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。
向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

int array[] = {27,15,19,18,28,34,65,49,25,37};

在这里插入图片描述

🥳🥳 ①下面介绍第一种向下调整为小堆
前提条件——左右子树都是小堆

//堆向下调整算法(小堆)
void AdjustDown(HPDataType* a, int n,int parent)
{int child = parent * 2 + 1;//向下调整while (parent < n){//找到较小的孩子节点if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = child * 2 + 1;}elsebreak;}
}

因为要调整为小堆,所以要找到孩子中较小的一个进行比较;
如果父节点小于较小的孩子节点则直接break不需要调整,因为向下调整的前提条件是——左右子树都是小堆
调整前:
在这里插入图片描述
调整后:在这里插入图片描述

💞💞Swap函数在这里

//交换函数
void Swap(HPDataType* a,HPDataType* b)
{HPDataType tmp = *a;*a = *b;*b = tmp;
}

🥳🥳②第二种向下调整为大堆;前提条件——左右子树都是大堆

//堆向下调整算法(大堆)
void AdjustDown(HPDataType* a, int n,int parent)
{int child = parent * 2 + 1;//向下调整while (child < n){//找到较大的孩子节点if (child + 1 < n && a[child] < a[child + 1]){child++;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = child * 2 + 1;}elsebreak;}
}

因为要调整为大堆,所以要找到孩子中较大的一个进行比较; 如果父节点大于于较大的孩子节点则直接break不需要调整,因为向下调整的前提条件是——左右子树都是大堆

🎉🎉我们这里使用小堆向下调整,大家可以根据自己的需求选择哦~

学习完堆向下调整我们知道只要左右子树是一个堆,那么我们就可以从根节点开始向下调整直到整个二叉树成为一个堆;💫💫
所以删除堆顶元素我们就可以将堆顶元素与最后一个元素交换一下位置,这样除了根节点,其余父子关系都没变,左右子树还是堆,删除交换后的最后一个元素(也就是原来的根节点);🎉🎉
我们再利用堆向下调整算法,将整个二叉树再次复原为堆。🥳🥳

堆顶元素删除

// 堆的删除,删除堆顶元素
void HeapPop(Heap* hp)
{assert(hp);assert(!HeapEmpty(hp));//判空函数将在后文介绍//交换首尾元素Swap(&hp->a[0], &hp->a[hp->size - 1]);//size要记得--,表示删除元素hp->size--;//向下调整算法AdjustDown(hp->a, hp->size, 0);}

4.堆的插入

void HeapPush(Heap* hp, HPDataType x)

我们知道堆的父节点必须都大于或小于子节点,那么往一个堆中插入元素是没办法保证大于或小于其父节点的,所以我们插入之后需要调整这个二叉树来保证堆;
这里就要用到堆向上调整算法了;注意下面是小堆的调整

堆向上调整算法

//向上调整
void AdjustUp(HPDataType* a,int child)
{//找到双亲节点int parent = (child - 1) / 2;//向上调整while (child > 0){if (a[parent] > a[child]){Swap(&a[parent], &a[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}
}

堆向上调整类似于向下调整也有大堆小堆之分,大家可以依照堆的向下调整自己试试看写一下大堆的向上调整

堆的插入

// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{assert(hp);//判断容量if (hp->size == hp->capacity)//容量满了扩容{int newcapacity = hp->capacity == 0 ? 0 : 2 * hp->capacity;HPDataType* new = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity);if (new == NULL){perror("realloc fail");return;}hp->a = new;hp->capacity = newcapacity;}//尾插hp->a[hp->size] = x;hp->size++;//向上调整算法AdjustUp(hp->a,hp->size-1);
}

这里要注意插入数据要判断容量,如果满了要用realloc函数扩容,对于realloc函数有疑问的可以看土土的动态内存函数博客🎉🎉——c语言动态内存函数介绍;
如果第一次扩容,就将空间扩为4个HPDataType,其余扩原来的两倍

5. 取堆顶的数据

HPDataType HeapTop(Heap* hp);

// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{assert(hp);assert(!HeapEmpty(hp));//判空return hp->a[0];//顶即下标为0的元素
}

6. 堆的数据个数

int HeapSize(Heap* hp)

// 堆的数据个数
int HeapSize(Heap* hp)
{assert(hp);return hp->size;
}

堆的数据个数即为结构体中的size,直接返回即可

7.堆的销毁

void HeapDestory(Heap* hp)

// 堆的销毁
void HeapDestory(Heap* hp)
{assert(hp);free(hp->a);hp->a = NULL;hp->capacity = 0;hp->size = 0;
}

,在内存中用realloc函数开辟空间用 free释放即可

💖💖判空函数在这里~
int HeapEmpty(Heap* hp)

// 堆的判空
int HeapEmpty(Heap* hp)
{assert(hp);return hp->size == 0;
}

8.堆实现代码如下

#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;
}
//交换函数
void Swap(HPDataType* a,HPDataType* b)
{HPDataType tmp = *a;*a = *b;*b = tmp;
}//堆向下调整算法
void AdjustDown(HPDataType* a, int n,int parent)
{//找到较小的孩子节点int child = parent * 2 + 1;//向下调整while (child < n){if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = child * 2 + 1;}elsebreak;}
}

测试代码如下:

#include"Heap.h"
int main()
{Heap hp;HeapInit(&hp);int a[] = { 65,100,70,32,50,60 };for (int i = 0; i < 6; i++){HeapPush(&hp, a[i]);}while (!HeapEmpty(&hp)){int top = HeapTop(&hp);printf("%d\n", top);HeapPop(&hp);}return 0;}

运行结果如下:
在这里插入图片描述
居然是升序诶~大家知道原因吗
可以根据上面的代码和介绍理解为自己解答哦~

三、结语

以上就是堆的介绍和实现啦~✨✨需要注意的是堆有大堆小堆之分,相应的函数也就有两种,这里简单介绍了小堆的实现,大堆介绍了一点,大家可以通过上面介绍的自己探索大堆的实现,此外堆向上调整与向下调整是一个重难点大家要多花时间去理解与记忆哦 ~完结撒花 ~💖🎉🎉🥳

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

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

相关文章

ai直播数字人:AI大模型应用开发的神奇世界

当AI技术的发展走向一个新的高峰&#xff0c;AI直播数字人逐渐成为人们关注的焦点。这种全新的数字人形态&#xff0c;通过大模型应用开发&#xff0c;带来了一个神奇世界。 在这个神奇世界里&#xff0c;AI直播数字人可以展现出与真实人类相媲美的外貌和声音。通过先进的图像…

[递归、搜索、回溯]----递归

前言 作者&#xff1a;小蜗牛向前冲 专栏&#xff1a;小蜗牛算法之路 专栏介绍&#xff1a;"蜗牛之道&#xff0c;攀登大厂高峰&#xff0c;让我们携手学习算法。在这个专栏中&#xff0c;将涵盖动态规划、贪心算法、回溯等高阶技巧&#xff0c;不定期为你奉上基础数据结构…

ROS 2基础概念#6:服务(Service)| ROS 2学习笔记

服务&#xff08;Service&#xff09;是 ROS 2 计算图中节点通信的另一种方法。 服务基于调用和响应模型&#xff0c;而不是主题的发布者-订阅者模型。 虽然主题允许节点订阅数据流并获取持续更新&#xff0c;但服务仅在客户端专门调用时才提供数据。 ROS 2服务的基本概念 ROS…

UE4升级UE5 蓝图节点变更汇总(4.26/27-5.2/5.3)

一、删除部分 Ploygon Editing删除 Polygon Editing这个在4.26、4.27中的插件&#xff0c;在5.1后彻底失效。 相关的蓝图&#xff0c;如编辑器蓝图 Generate mapping UVs等&#xff0c;均失效。 如需相关功能&#xff0c;请改成Dynamic Mesh下的方法。 GetSupportedClass删…

微服务超大Excel文件导出方案优化

1、在导出Excel时经常会碰到文件过大&#xff0c;导出特别慢 2、微服务限制了请求超时时间&#xff0c;文件过大情况必然超时 优化思路&#xff1a; 1、文件过大时通过文件拆分、打包压缩zip&#xff0c;然后上传到oss,并设置有效期&#xff08;30天过期&#xff09; 2、把…

便捷在线导入:完整Axure元件库集合,让你的设计更高效!

Axure元件库包含基本的工具组件&#xff0c;可以使原型绘制节省大量的重复工作&#xff0c;保持整个设计页面的一致性和标准化&#xff0c;同时显得专业。Axure元件库就像我们日常生活中的门把手、自行车踏板和桌子上的螺丝钉&#xff0c;需要组装才能使用。作为一名成熟的产品…

搜索引擎都没流量啦,官网建设还有啥意义?

百度等搜索引擎都没啥流量了&#xff0c;再建设官网还有啥用&#xff1f;如果你把官网定位于获客&#xff0c;那真的没啥太大用处&#xff0c;但是官网不仅仅是用来获客的。 一、搜索引擎的流量被稀释了 搜索引擎流量减少的原因有多个&#xff0c; 1. 社交媒体的崛起&#xf…

数据库原理实验课(1)

目录 实验内容 安装头歌中的相关内容 具体过程 完结撒花~ 我也是第一次接触oracle的相关软件和操作&#xff0c;所以是一次傻瓜式教学记录 实验内容 安装头歌中的相关内容 具体过程 这是我在百度网盘中下载解压出来的oracle文件夹内的全部内容&#xff08;可能有因为安装完…

可编程线性霍尔传感器 IC

一、产品概述 CC6521/2 是一款高性能的可编程线性霍尔传感器 IC&#xff0c;采用先进的 BiCMOS 制程生产&#xff0c;具有霍尔系数高的优点&#xff0c;芯片内部包含了高灵敏度 霍尔传感器&#xff0c;霍尔信号预放大器&#xff0c;高精度的霍尔温度补偿单元&#xff0c;振荡…

EOCR电动机保护器在冶金行业的应用具有显著的意义和优势

冶金行业是一个对电动机保护和控制设备需求非常迫切的行业&#xff0c;因为电动机是拖动机械的基础&#xff0c;广泛应用于各种动力机械中。 冶金厂中的电动机需要承受高温、高湿、高粉尘等恶劣环境&#xff0c;同时还需要应对频繁的启动和停止&#xff0c;以及电压不稳定等问…

Java中的优先队列PriorityQueue如何排序

目录 一、基本数据类型的排序 &#xff08;1&#xff09;升序 &#xff08;2&#xff09;降序 二、自定义类型如何排序 &#xff08;1&#xff09;升序 &#xff08;2&#xff09;降序 既然大家想要了解优先队列的排序&#xff0c;那么说明已经知道什么事优先队列了&…

HNU-算法设计与分析-甘晴void学习感悟

前言 算法设计与分析&#xff0c;仅就课程而言&#xff0c;似乎是数据结构与算法分析的延续 教材使用&#xff1a; 课程 关于课程&#xff0c;橙学长讲的非常清晰&#xff0c;我深以为然。 HNUCS-大三课程概览-CSDN博客文章浏览阅读1.3k次&#xff0c;点赞5次&#xff0c;收…