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

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

二叉树的性质:

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

  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 赋值

目录
相关文章
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
935 140
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
数据采集 JSON 数据可视化
JSON数据解析实战:从嵌套结构到结构化表格
在信息爆炸的时代,从杂乱数据中提取精准知识图谱是数据侦探的挑战。本文以Google Scholar为例,解析嵌套JSON数据,提取文献信息并转换为结构化表格,通过Graphviz制作技术关系图谱,揭示文献间的隐秘联系。代码涵盖代理IP、请求头设置、JSON解析及可视化,提供完整实战案例。
894 4
JSON数据解析实战:从嵌套结构到结构化表格
|
存储 机器学习/深度学习 算法
C 408—《数据结构》图、查找、排序专题考点(含解析)
408考研——《数据结构》图,查找和排序专题考点选择题汇总(含解析)。
1481 29
|
存储 机器学习/深度学习 人工智能
C 408—《数据结构》易错考点200题(含解析)
408考研——《数据结构》精选易错考点200题(含解析)。
1914 27
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
646 5
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
1411 2
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
1727 1
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
896 16
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
436 59
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
1168 77

推荐镜像

更多
  • DNS