【数据结构】 实现 堆 结构 ---超细致解析(上)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 【数据结构】 实现 堆 结构 ---超细致解析(上)

二叉树的性质:

在我们实现堆之前我们要知道堆的实现是依靠的是二叉树 所以我们在实现对之前要了解一下二叉树的基本性质:>

  1. 如果根节点的层数为1,则一个非空二叉树的第 i 层上最多有2^(i-1)个节点
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大节点数是2^h - 1
  3. 对于任何一棵二叉树,如果度为0的节点个数是n0,度为2的分支节点个数为n2,则有n0=n2+1
  4. 如果说根节点的层数为1,那么具有那个节点的满二叉树的深度 h=log2(n+1);

4fa23cbc0b4a443995eabd9515c5ee92.png

这些就是我们二叉树的一些基本性质


二叉树的存储结构:

二叉树一般有两种存储结构 一个顺序结构 一个链式结构


顺序存储:

顺序存储顾名思义 就是存储的数据是有一定顺序的 所以顺序存储就是用数组来进行存储 但是使用顺序存储一般用来存储完全二叉树 因为不是完全二叉树会有空间的浪费(就是有些地方应该为NULL 那么在数组里面这些地方也应该空着 它们只能属于自己的位置)

5d1043c5c5bf4db7b7d05be2aae4acdc.png像这样大家应该就知道如果说不是完全二叉树使用顺序结构的话 会有空间的浪费 数据越多浪费的空间也可能更多


链式存储:

链式存储意思就是用链表来表示 一个链表的节点就包括 这个节点的数据和左右节点的指针

typedef struct BinaryTreeNode
{
  int data;
  struct BinaryTreeNode* left;
  struct BinaryTreeNode* right;
}BTNode;


堆的概念和性质:

堆 其实就是 一个完全二叉树 其中堆又分为 小堆 和 大堆

小堆 就是 根节点是所有数据中最小的

大堆 就是 根节点是所有数据中最大的


堆的实现:

首先这里我们就用 数组 的方式来存储数据

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

另外有个点大家要注意 我们的堆是不支持什么在 中间 插入删除数据的 这种操作是顺序表中使用的 但我们的堆虽然是使用的数组的结构 但那只是物理上面的 逻辑上面可不是那样的哦

这里我们为什么还有一个size capacity呢 这两个参数是用来判断是否扩容的 我们这里设置的是一个动态增长的数组


堆的初始化:

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


堆的插入:

我们先了解一下堆的插入是如何实现 首先我们的堆的结构是一个动态的数组 我们在他的尾部插入数据 但大家想想仅仅只是把数据放进去就完了嘛 我们上面说过我们堆里面的数据位置是有讲究的 如果说随便改变是有可能会把我们之前建立的结构破坏的

所以如果我们建立的是一个小堆的话 现在放进去一个较小的数据 那么这个数据肯定是要往前面进行调整的 不然我们的堆就不是小堆 :>

488057a6e2ff4d59aab2311635cef3be.png

看过上图 大家应该知道我们 因给如何调整我们的堆结构了把:

就是  向上调整 

image.gif

这个就是我们的向上调整的整体操作

void HeapPush(Heap* hp, HPDataType x)
{
  if (hp->_size == hp->_capacity)
  {
    int newcapcity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;
    HPDataType* tmp=(HPDataType *)malloc(newcapcity * sizeof( HPDataType));
    assert(tmp);
    hp->_a = tmp;
  }
  hp->_a[hp->_size++] = x;
  AdjustUp(hp->_a, hp->_size - 1);//因为我们我们调整是从最后一个数据开始调 所以要传他的下标
}

因为我们堆的实现物理上还是依靠的顺序表 虽说结构上是树 但我们在插入数据的时候 难免会遇到要扩容的情况 所以我们使用了 sizecapacity 来实时监控我们的空间

然后就来看我们的向上调整函数:


向上调整函数:

在实现我们的向上调整函数之前 我们首先要了解 树中 父亲和孩子的关系

左孩子=父亲×2+1

右孩子=父亲×2+2

然后大家想想 其实无论奇数还是偶数 -1÷2 的结果都是一样的 我的编译器 ÷ 是默认的向下取整 带入几个数算了就知道他们的结果都是一样的 但你要-2÷2就不太好了


void AdjustUp(HPDataType* a,int child)
{
  assert(a);
  size_t parent = (child - 1) >> 1;
  while (child > 0)
  {
    if (a[child] < a[parent])
    {
      swap(a+child, a+parent);
      child = parent;
      parent= (child - 1) >> 1;
    }
    else
    {
      break;
    }
  }
}

b24b32923c884b36b74562f6e35c4ebb.gif看到这个图大家应该明白我们的child 排到0时 就不用再继续往上调整了

所以我们 设置的外部循环是 child>0  至于为什么不用parent判断 因为parent不会小于0

我们的child等于0的时候 (0-1)/2 parent还是等于0的

里面设置一个if 小于就交换 大于就不用再换了 大于一个数那它都大于它上面的了

然后重新给我们的 child parent 赋值

目录
相关文章
|
25天前
|
人工智能
歌词结构的巧妙安排:写歌词的方法与技巧解析,妙笔生词AI智能写歌词软件
歌词创作是一门艺术,关键在于巧妙的结构安排。开头需迅速吸引听众,主体部分要坚实且富有逻辑,结尾则应留下深刻印象。《妙笔生词智能写歌词软件》提供多种 AI 功能,帮助创作者找到灵感,优化歌词结构,写出打动人心的作品。
|
16天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
58 16
|
21天前
|
存储 消息中间件 NoSQL
Redis数据结构:List类型全面解析
Redis数据结构——List类型全面解析:存储多个有序的字符串,列表中每个字符串成为元素 Eelement,最多可以存储 2^32-1 个元素。可对列表两端插入(push)和弹出(pop)、获取指定范围的元素列表等,常见命令。 底层数据结构:3.2版本之前,底层采用**压缩链表ZipList**和**双向链表LinkedList**;3.2版本之后,底层数据结构为**快速链表QuickList** 列表是一种比较灵活的数据结构,可以充当栈、队列、阻塞队列,在实际开发中有很多应用场景。
|
17天前
|
机器学习/深度学习 自然语言处理 数据管理
GraphRAG核心组件解析:图结构与检索增强生成
【10月更文挑战第28天】在当今数据科学领域,自然语言处理(NLP)和图数据管理技术的发展日新月异。GraphRAG(Graph Retrieval-Augmented Generation)作为一种结合了图结构和检索增强生成的创新方法,已经在多个应用场景中展现出巨大的潜力。作为一名数据科学家,我对GraphRAG的核心组件进行了深入研究,并在此分享我的理解和实践经验。
39 0
|
20天前
|
存储 NoSQL 关系型数据库
Redis的ZSet底层数据结构,ZSet类型全面解析
Redis的ZSet底层数据结构,ZSet类型全面解析;应用场景、底层结构、常用命令;压缩列表ZipList、跳表SkipList;B+树与跳表对比,MySQL为什么使用B+树;ZSet为什么用跳表,而不是B+树、红黑树、二叉树
|
23天前
光纤电缆(FOC)的结构深度解析
【10月更文挑战第21天】
38 0
|
1月前
探索顺序结构:栈的实现方式
探索顺序结构:栈的实现方式
|
17天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
91 9
|
8天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
16 1
|
10天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。

推荐镜像

更多