我的编程空间,编程开发者的网络收藏夹
学习永远不晚

【数据结构】-向上调整算法和向下调整算法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

【数据结构】-向上调整算法和向下调整算法

作者:小树苗渴望变成参天大树
作者宣言:认真写好每一篇博客
作者gitee:gitee
在这里插入图片描述
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!


前言

今天我们来堆,堆是建立再有二叉树基础的前提下去学习的,采用的是二叉树的顺序存储方式,所以结构类似于满二叉树,会介绍堆的概念,以及模拟一个堆出来,本篇知识量有一点大,希望读者可以耐心的阅读下去,并且真正学会堆


一、堆的概念及结构

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

堆的性质:
1.堆中某个节点的值总是不大于或不小于其父节点的值;
2.堆总是一棵完全二叉树。
3.堆顶一定是整个堆中最大或者最小的数据

我们只需要看堆的性质即可
我们来看一下两种类型的堆
在这里插入图片描述

看到现在我们要掌握什么是堆,什么是大根堆,什么是小根堆,以及怎么通过堆写成数组的形式,怎么通过数组来写成堆的形式

注意:堆里面的元素如果都相等的话,即可以看成大根堆,也可以看成小根堆

二、堆的创建(以大根堆为例)

我们刚才说过对于堆我们采取数组的方式来存储,还要满足可以往堆里面插入和删除数据时必须还得是堆的情况,我们采取顺序表的创建方式来创建堆

typedef int HPDataType;typedef struct Heap{HPDataType* a;//定义一个数组int size;//数组里面的有效数据个数int capacity;//此时数组容量大小}Heap;

初始化和顺序表初始化一样:

void HPInit(Heap* php){php->a = (HPDataType*)malloc(sizeof(HPDataType) * 4);if (php->a == NULL){perror("malloc:");return;}php->size = 0;php->capacity = 4;}

我们重点来介绍堆的插入和删除

三、堆的插入

我们插入数组的树必须保证原数组依然是堆,这就很有难度,我们先来看图讲解:
在这里插入图片描述
我们采取的是向上调整算法,肯定是先插入左孩子,再插入右孩子,所以插入的是右孩子不必考虑左孩子的值是否比父亲大等情况,我们只需要把插入的孩子和父亲比较就好了,当parent<0就结束,没有交换的时候表示已经是堆了,因为你再插入的之前他就是一个堆了

我们来看向上调整算法代码:

void Swap(HPDataType* p1, HPDataType* p2){HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;}void AdjustUp(HPDataType* a, int child)//传入的数组和插入的孩子再数组的下标{assert(a);int parent = (child - 1) / 2;//找到父亲结点对应的下标while (child > 0){if (a[parent] < a[child])//以大根堆为例,小根堆换一下符号即可{Swap(&a[parent], &a[child]);//交换child = parent;parent = (child - 1) / 2;//迭代}else{break;}}}

因为都是一步步的向上进行调整,所有就叫向上调整算法

我们看堆的插入:

void HeapPush(Heap* php, HPDataType x){assert(php);if (php->size == php->capacity){HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * 2 * php->capacity);if (tmp == NULL){perror("realloc:");return;}else{php->a = tmp;php->capacity *= 2;}}php->a[php->size++] = x;//先插入,再把数组弄成堆的形式AdjustUp(php->a, php->size - 1);//向上调整算法}

四、堆的删除

我们来想一下,堆的删除,应该还是删除那一个数据,是堆头还是堆尾,我们可以来想想,如果删除堆尾,有什么意义,即不一定是最大的数据,也不是最小的数据,没有什么意义,所以我们选择删除堆头的数据,那我们怎么去删除呢

有的人会想,再顺序表的时候,我们进行头删的时候,把前面的数据直接往前面挪一位,所以我们再堆的时候可不可以也这样搞,我们来画图看看:
在这里插入图片描述

我们发现采取挪数据的方式并不可取,父亲与孩子的关系全部乱了,那我们应该怎么去解决删数据的问题呢??

我们想到一种方法,因为插入数据是在尾部插入,插入之前是堆,不影响,那我们再删除的时候再从尾部删除不就可以了,但是我要删除的数据是堆顶的数据啊,怎么删除尾部的呢,我们可以交换一下,那交换了这个堆可能就不是堆了,但是堆里面的结点的那个对应关系是不是没有破坏,我们重新调整就好了
来看图:
在这里插入图片描述
我们看到我们采取的向下天正算法,把交换好的数据重新调整成堆,我们来直观的看一下向下调整算法的代码

void Swap(HPDataType* p1, HPDataType* p2){HPDataType tmp = *p1;*p1 = *p2;*p2 = 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 += 1;}if (a[parent] < a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}}

不会的可以走读一下代码看看是怎么实现的
我们来看一下删除的完整代码:

void HeapPop(Heap* php){assert(php);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);//因为都是从堆顶调整,所以parent传的就是0}

注意:向上调整算法和向下调整算法都有一个前提条件,被调整的那个结点,左右子树都必须是堆

对于堆的两款大骨头我们几乎啃完了,接下来大部分都是顺序表玩生下来的操作了

五、堆顶的元素

HPDataType* HeapTop(Heap* php){assert(php);return php->a[0];}

六、判断堆是否为空

bool HeapEmtpy(Heap* php){assert(php);return php->size == 0;}

七、堆里有多少元素

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

八、代码测试

int main(){Heap php;HPInit(&php);HeapPush(&php,1);HeapPush(&php, 2);HeapPush(&php, 34);HeapPush(&php, 4);HeapPush(&php, 23);HeapPush(&php, 16);HeapPush(&php, 7);while (!HeapEmtpy(&php)){printf("%d ", HeapTop(&php));HeapPop(&php);}}

在这里插入图片描述
我们看到我们手动模拟出来一个堆了,相信大家学到这里对堆有了不一样的理解

完整代码:

#include"Heap.h"void HPInit(Heap* php){php->a = (HPDataType*)malloc(sizeof(HPDataType) * 4);if (php->a == NULL){perror("malloc:");return;}php->size = 0;php->capacity = 4;}void Swap(HPDataType* p1, HPDataType* p2){HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;}void AdjustUp(HPDataType* a, int child){assert(a);int parent = (child - 1) / 2;while (child > 0){if (a[parent] < a[child]){Swap(&a[parent], &a[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void HeapPush(Heap* php, HPDataType x){assert(php);if (php->size == php->capacity){HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * 2 * php->capacity);if (tmp == NULL){perror("realloc:");return;}else{php->a = tmp;php->capacity *= 2;}}php->a[php->size++] = x;AdjustUp(php->a, php->size - 1);//向上调整算法}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 += 1;}if (a[parent] < a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void HeapPop(Heap* php){assert(php);Swap(&php->a[0], &php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);}HPDataType* HeapTop(Heap* php){assert(php);return php->a[0];}bool HeapEmtpy(Heap* php){assert(php);return php->size == 0;}int HeapSize(Heap* php){assert(php);return php->size;}#include#include#include#includetypedef int HPDataType;typedef struct Heap{HPDataType* a;int size;int capacity;}Heap;void HPInit(Heap* php);void HeapPush(Heap* php, HPDataType x);void HeapPop(Heap* php);HPDataType* HeapTop(Heap* php);bool HeapEmtpy(Heap* php);int HeapSize(Heap* php);

来源地址:https://blog.csdn.net/qq_69369227/article/details/129758954

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

【数据结构】-向上调整算法和向下调整算法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java数据结构与算法之栈(动力节点Java学院整理)

stack,中文翻译为堆栈,其实指的是栈,heap,堆。这里讲的是数据结构的栈,不是内存分配里面的堆和栈。栈是先进后出的数据的结构,好比你碟子一个一个堆起来,最后放的那个是堆在最上面的。队列就是排队买苹果,先去的那个可以先买。栈public
2023-05-31

Java数据结构与算法之选择排序(动力节点java学院整理)

每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。代码public class ChoseSort { //constructor without parameters
2023-05-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录