速学数据结构 | 二叉树堆的实现详解篇

简介: 速学数据结构 | 二叉树堆的实现详解篇

📋 前言

  🌈hello! 各位宝子们大家好啊,二叉树的概念大家都了解了那么我们今天就看一下

  ⛳️顺序存储究竟是怎么存储的,如何实现增删查改这些功能。

  📚本期文章收录在《数据结构&算法》,大家有兴趣可以看看呐

  ⛺️ 欢迎铁汁们 ✔️ 点赞 👍 收藏 ⭐留言 📝!

一、堆的概念

二叉树顺序存储的最大的一个应用就是堆,也是我们后面学习堆排序以及我们日常生活中的 找大小 TOPK 问题的应用。

  • 那么什么是堆呢?

堆就是由二叉树组成把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中。

  • 其中他一定是一个完全二叉树或者满二叉树
  • 堆中某个结点的值总是不大于或不小于其父结点的值;

其中堆又分大堆和小堆:

  • 将根结点最大的堆叫做最大堆或大根堆。
  • 根结点最小的堆叫做最小堆或小根堆。

二、堆的实现

二叉树的最大应用就是“堆”,所以我们今天来看一下堆是怎么实现的他到底有什么功能呢? 他的结构到底是什么?

  • 其实堆的结构和二叉树是一模一样的,只不过存储方式有差别

我们上面介绍过堆中某个结点的值总是不大于或不小于其父结点的值:

2.1 堆的结构

堆的结构很简单前面介绍的时候其实已经介绍过了:

  • 我们采用数组存储的方法,使用size来记录堆的个数
  • capacity来标识堆的容量

📚 代码演示:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
typedef int HPDataType;
typedef struct Heap
{
  HPDataType* a;
  int size;
  int capacity;
}Heap;

2.2 堆的销毁

俗话说做题先从容易得写诶这次我们就先来从堆的销毁来写这个大家在熟悉不过了:

  • 既然是动态申请的空间直接释放就好了
  • 其他 数据个数 和 容量 置为零

📚 代码演示:

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

2.3 堆的插入

堆的插入就是本篇文章的重点了,堆的插入方式有很多比如说插入之后向上取整,或者向下取整我们选那个呢?

  • 🔥 因为堆要向下取整的时候,左右子树一定要是堆
  • 所以一般选取的是尾插向上取整

向上取整算法

上述就是向上取整的全部流程就是拿我们插入的数据和他的 父节点 进行比较然后调整交换:

  • 这里有一个特点 parent = (child-1)/ 2 ;
  • 父节点等于子节点 -1 除二

所以我们可以根据这一特性来进行循环调整堆

📚 代码演示:

//向上调整
void adjustup(HeapTypeData* 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;
    }
  }
}

这样我们不就把堆的插入OK了吗?既然建堆都会了那么插入还不简单嘛?

📑注意事项:

  1. 检查容量进行扩容
  2. 注意写入数据
  3. 有效个数要++

📚 代码演示:

//堆的插入
void HeapPush(hp* hp, int x)
{
  assert(hp);
  if (hp->capacity == hp->size)
  {
    int newcapacity = hp->capacity * 2;
    HeapTypeData* tmp = (HeapTypeData*)realloc(hp->a, newcapacity * sizeof(HeapTypeData));
    if (tmp == NULL)
    {
      perror("realloc file");
      exit(-1);
    }
    hp->a = tmp;
    hp->capacity = newcapacity;
  }
  hp->a[hp->size] = x;
  hp->size++;
  adjustup(hp->a, hp->size - 1);
}

2.4 堆的删除

堆的删除一般我们都是删除其堆顶的数据:

  • 所以一般是采用向下取整,把堆顶和堆尾进行互换然后再删除堆尾。
  • 把堆顶数据向下调整

这里要控制好循环结束的条件当child < 堆的个数的时候就停止:

  • 而且左孩子节点一定是 child = parent* 2+1;

📚 代码演示:

//向下调整
void adjustdown(HeapTypeData* a, int n, int parent)
{
  int child = parent* 2+1;
  while (child < n)
  {
    if (child+1 < n && a[child + 1] < a[child])
    {
      child++;
    }
    if (a[child] < a[parent])
    {
      Swap(&a[child], &a[parent]);
      parent = child;
      child = parent*2 +1;
    }
    else
    {
      break;
    }
  }
}

然后我们进行交换堆顶 和堆数据在进行更改有效个数

  • 调整一下堆的删除就完了

📚 代码演示:

//堆的删除
void HeapPop(hp* hp)
{
  assert(hp);
  Swap(&hp->a[0], &hp->a[hp->size-1]);
  --hp->size;
  adjustdown(hp->a, hp->size, 0);
}

2.5 取堆顶的数据

这个很简单啦!直接秒杀堆顶数据,我们是从数组开头顺序存放的所以 hp->a[ 0 ]

  • 数组访问就好了

📚 代码演示:

//堆顶元素
void HeapTop(hp* hp)
{
  assert(hp);
  return hp->a[0];
}

2.6 堆的数据个数

数据个数 hp->size就是用来记录有效数据个数的我们直接返回就可以了:

📚 代码演示:

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

2.7 堆的判空

当堆的有效数据为零的时候堆就是空的

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

📝全篇总结

☁️ 好了以上就是全部的建堆代码啦,大家快去实践起来吧!

看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注

💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖

拜托拜托这个真的很重要!

你们的点赞就是博主更新最大的动力!

有问题可以评论或者私信呢秒回哦。

目录
相关文章
|
27天前
|
存储 机器学习/深度学习
【数据结构】二叉树全攻略,从实现到应用详解
本文介绍了树形结构及其重要类型——二叉树。树由若干节点组成,具有层次关系。二叉树每个节点最多有两个子树,分为左子树和右子树。文中详细描述了二叉树的不同类型,如完全二叉树、满二叉树、平衡二叉树及搜索二叉树,并阐述了二叉树的基本性质与存储方式。此外,还介绍了二叉树的实现方法,包括节点定义、遍历方式(前序、中序、后序、层序遍历),并提供了多个示例代码,帮助理解二叉树的基本操作。
42 13
【数据结构】二叉树全攻略,从实现到应用详解
|
4月前
|
存储 算法
【数据结构和算法】--- 二叉树(4)--二叉树链式结构的实现(2)
【数据结构和算法】--- 二叉树(4)--二叉树链式结构的实现(2)
33 0
|
24天前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
24天前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
24天前
|
存储 C语言
数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树
本文详细介绍了树与二叉树的应用,涵盖哈夫曼树与哈夫曼编码、并查集以及二叉排序树等内容。首先讲解了哈夫曼树的构造方法及其在数据压缩中的应用;接着介绍了并查集的基本概念、存储结构及优化方法;随后探讨了二叉排序树的定义、查找、插入和删除操作;最后阐述了平衡二叉树的概念及其在保证树平衡状态下的插入和删除操作。通过本文,读者可以全面了解树与二叉树在实际问题中的应用技巧和优化策略。
|
2月前
|
存储
【初阶数据结构篇】二叉树基础概念
有⼀个特殊的结点,称为根结点,根结点没有前驱结点。
|
2月前
|
存储 Linux Windows
【数据结构】二叉树
【数据结构】二叉树
|
2月前
|
存储 算法 Linux
【数据结构】树、二叉树与堆(长期维护)(1)
【数据结构】树、二叉树与堆(长期维护)(1)
|
2月前
|
算法
【数据结构】树、二叉树与堆(长期维护)(2)
【数据结构】树、二叉树与堆(长期维护)(2)
【数据结构】树、二叉树与堆(长期维护)(2)
|
2月前
|
算法 Java
数据结构二叉树
这篇文章讨论了数据结构中的二叉树,并提供了一个二叉树中序遍历的算法示例,包括给定二叉树的根节点返回中序遍历结果的Java代码实现。
数据结构二叉树