二叉树顺序结构与堆的概念及性质(c语言实现堆)

上次介绍了树,二叉树的基本概念结构及性质:二叉树数据结构:深入了解二叉树的概念、特性与结构

今天带来的是:二叉树顺序结构与堆的概念及性质,还会用c语言来实现堆


文章目录

  • 1. 二叉树的顺序结构
  • 2.堆的概念和结构
  • 3.堆的实现(小堆)
    • 3.1项目文件规划
    • 3.2结构体和各功能一览(Heap.h)
    • 3.3重要函数详解(Heap.c)
      • 3.3.1堆向上调整算法
      • 3.3.2堆向下调整算法
    • 3.4各功能实现(Heap.c)
      • 初始化和销毁
      • 插入
      • 删除堆顶
      • 返回根(堆顶)的存储的数据
      • 节点数量
      • 是否为空
    • 3.5建堆时间复杂度


1. 二叉树的顺序结构

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。完全二叉树就比较适合使用顺序结构存储(数组)。现实中我们通常把(一种二叉树)使用顺序结构的数组来存储

注意:此堆非“彼堆”——操作系统虚拟进程地址空间中的堆。二者一个是一个是数据结构,一个是操作系统中管理内存的一块区域


2.堆的概念和结构

堆需要满足两点

  1. 堆是一个完全二叉树,即除了最底层,其他层都是完全填满,最底层从左到右填充
  2. 堆中的每个节点的值都必须大于等于(最大堆)或小于等于(最小堆)其子节点的值

根据节点值的大小关系,堆可以分为最大堆和最小堆。在最大堆中,根节点的值最大,每个节点的值都大于等于其子节点的值。在最小堆中,根节点的值最小,每个节点的值都小于等于其子节点的值

请添加图片描述

请添加图片描述


3.堆的实现(小堆)

3.1项目文件规划

请添加图片描述

  • 头文件Heap.h:用来基础准备(常量定义,typedef),链表表的基本框架,函数的声明
  • 源文件Heap.c:用来各种功能函数的具体实现
  • 源文件test.c:用来测试功能是否有问题,进行基本功能的使用

3.2结构体和各功能一览(Heap.h)

typedef int HPDataType;typedef struct Heap//用顺序表来实现,跟顺序表的结构一样
{HPDataType* a;int size;//数量int capacity;//容量
}HP;void HeapInit(HP* php);//初始化
void HeapDestroy(HP* php);//销毁void HeapPush(HP* php, HPDataType x);//插入
// 规定删除堆顶(根节点)
void HeapPop(HP* php);//删除HPDataType HeapTop(HP* php);//返回根(堆顶)的存储的数据int HeapSize(HP* php);//堆的数据个数bool HeapEmpty(HP* php);//是否为空

3.3重要函数详解(Heap.c)

3.3.1堆向上调整算法

i位置节点的双亲序号:(i-1)/2

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)//传入数组和下标索引
{int father = (child - 1) / 2;//利用公式来算出父亲节点下标while (child > 0){if (a[child] < a[father]){Swap(&a[child], &a[father]);//更新下标child = father;father = (father - 1) / 2;}else{break;//一旦符合小堆了,就直接退出}}
}

Swap 函数用于交换两个指针指向的值,而 AdjustUp 函数用于通过比较子节点与父节点并在有必要时交换它们来调整堆的结构,然后向上移动树,直到满足堆的性质

3.3.2堆向下调整算法

i位置的左孩子是 2 ∗ i + 1 2*i+1 2i+1,右孩子 2 ∗ i + 2 2*i+2 2i+2

void AdjustDown(HPDataType* a, int n, int father)
{int child = father * 2 + 1;//假设左孩子小  找出两者较小的来跟父节点比(大堆就找二者中较大的了)while (child < n){if (child + 1 < n && a[child] > a[child + 1]){child++;}if (a[child] < a[father]){Swap(&a[child], &a[father]);father = child;child = father * 2 + 1;}else{break;}}
}
  1. 给定一个数组 a,表示堆的结构,以及数组的大小 n 和要进行调整的父节点的索引 father
  2. 计算父节点的左孩子的索引为 father * 2 + 1
  3. 进入一个 while 循环,只要左孩子的索引小于 n (不会出数组)就会继续
  4. 在循环内部,首先检查右孩子是否存在且右孩子的值是否大于左孩子的值,如果是,则更新 child 为右孩子的索引。这是为了找出左右孩子中值较大的那个
  5. 比较左孩子的值和父节点的值,如果左孩子的值小于父节点的值,则调用 Swap 函数交换这两个索引处的值,并更新 fatherchild 的值,然后重新计算 child 的索引。这一步的目的是将较大的子节点值向上移动,以满足堆的性质
  6. 如果左孩子的值不小于父节点的值,则跳出循环,因为堆的性质已经满足

3.4各功能实现(Heap.c)

初始化和销毁

void HeapInit(HP* php)
{assert(php);php->a = NULL;php->size = php->capacity = 0;
}void HeapDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->size = php->capacity = 0;
}

插入

void HeapPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity)//检查有没有满{int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));if (tmp == NULL){perror("realloc fail");return -1;}php->a = tmp;php->capacity = newCapacity;}//开始插入php->a[php->size] = x;php->size++;//要确保是小堆AdjustUp(php->a, php->size - 1);
}

删除堆顶

void HeapPop(HP* php)//最外面那个和堆顶交换后,删去最外面的,再把新堆顶向下调整成小堆
{assert(php);assert(php->size > 0);//保证有东西可以删Swap(php->a[0], php->a[php->size - 1]);php->size--;AdjustDown(php->a, php->size, 0);
}

返回根(堆顶)的存储的数据

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

节点数量

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

是否为空

bool HeapEmpty(HP* php)
{assert(php);return php->size == 0;
}

3.5建堆时间复杂度

请添加图片描述

建堆的时间复杂度为O(N)


这次就到这里啦,下一次就利用这次的对来解决几个问题。感谢大家的支持!!!

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

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

相关文章

C++提高编程二(STL、Vector容器、string字符串)

文章目录 STL容器算法迭代器初识Vector存放自定义数据类型Vector容器嵌套容器string构造函数string赋值操作string字符串拼接string查找和替换string字符串比较string字符存取string插入和删除string子串 STL STL&#xff08;Standard Template Library&#xff09;&#xff0…

【多传感器融合导航论文阅读】

多传感器融合导航论文积累 知识点总结因子图一致因子图 文献阅读笔记[IF 18.6] 知识点总结 因子图 Factor Graph 是概率图的一种&#xff0c;是对函数因子分解的表示图&#xff0c;一般内含两种节点&#xff0c;变量节点和函数节点。 因子图存在着&#xff1a;两类节点&#…

css 用多个阴影做出光斑投影的效果 box-shadow

css 用多个阴影做出光斑投影的效果 box-shadow 你首先需要知道的一点是 box-shadow 可以接收多个值&#xff0c;也就是可以设置多个阴影&#xff0c;这样就可以做一个类似光斑投影的效果。 一、效果 二、代码 里面用到了我一些 scss 工具方法&#xff0c;不过不影响&#xf…

3D视觉-结构光测量-多线结构光测量

工作原理 多线结构光测量在测量方式上类似上述线结构光测量&#xff0c;但是两者也有着一些明显的差别。这种形式的结构光测量&#xff0c;也常常被成为面结构光测量。首先激光器发出电光源通过通过光栅的调制产生多个切片光束&#xff0c;这些切片光束照射到待测物体表面后形成…

C++线性表

线性表的定义及其运算 线性表是一种最简单、最基本也是最常用的线性结构。在线性结构中&#xff0c;数据元素之间存在一个对一个的线性关系&#xff0c;数据元素“一个接一个地排列”。在一个线性表中&#xff0c;数据元素的类型是相同的&#xff0c;或者说&#xff0c;线性表…

Git基础学习_p1

文章目录 一、前言二、Git手册学习2.1 Git介绍&前置知识2.2 Git教程2.2.1 导入新项目2.2.2 做更改2.2.3 Git追踪内容而非文件2.2.4 查看项目历史2.2.5 管理分支&#x1f53a;2.2.6 用Git来协同工作2.2.7 查看历史 三、结尾 一、前言 Git相信大部分从事软件工作的人都听说过…

shell编程一

shell 定义 Shell 也是一种程序设计语言&#xff0c;它有变量&#xff0c;关键字&#xff0c;各种控制语句&#xff0c;有自己的语法结构&#xff0c;利用shell程序设计语 可以编写功能强、代码简短的程序 #! Shebang 定义解释器 shell的分类和切换 # cat /etc/shells /bin/sh…

win部署stable-diffusion

win部署stable-diffusion 1.环境2.模型3.使用4.效果 1.环境 首先下载stable-diffusion-webui&#xff0c;这个包了一层ui&#xff0c;特别好用。 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git然后搭建conda环境。 这里的pytorch&#xff0c;自己去…

鸿蒙HarmonyOS-带笔锋手写板(三)

笔者用ArkTS 写了一个简单的带笔锋的手写板应用&#xff0c;并且可以将手写内容保存为图片。 一、效果图 手写效果如下&#xff08;在鸿蒙手机模拟器上运行&#xff0c;手写时反应可能会有点慢&#xff09; 二、实现方法 参考文章&#xff1a; 支持笔锋效果的手写签字控件_a…

在Linux上搭建Maven仓库的实战教程

引言 在Java开发中&#xff0c;Maven作为项目构建和依赖管理的重要工具&#xff0c;其仓库的搭建至关重要。本文将手把手教你如何在Linux系统上安装并配置Nexus Repository Manager 3&#xff08;简称Nexus 3&#xff09;&#xff0c;从而创建一个私有的Maven仓库。 步骤一&a…

论文阅读——Slide-Transformer(cvpr2023)

Slide-Transformer: Hierarchical Vision Transformer with Local Self-Attention 一、分析 1、改进transformer的几个思路&#xff1a; &#xff08;1&#xff09;将全局感受野控制在较小区域&#xff0c;如&#xff1a;PVT&#xff0c;DAT&#xff0c;使用稀疏全局注意力来…

两种汇编的实验

week04 一、汇编-1二、汇编-2 一、汇编-1 1 通过输入gcc -S -o main.s main.c -m32 将下面c程序”week0401学号.c“编译成汇编代码 int g(int x){ return x3; } int f(int x){ int i 学号后两位&#xff1b; return g(x)i; } int main(void){ return f(8)1; } 2. 删除汇编代码…