二叉树顺序结构与堆的概念及性质(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.mzph.cn/news/585810.shtml

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

相关文章

推荐几个开源HTTP服务接口快速生成工具

在现在流行微服务、前后端分离软件开发架构下&#xff0c;基于标准RESTful/JSON的HTTP接口已经成为主流。在实际业务中有很多需要快速开发调用数据服务接口的需求&#xff0c;但团队中缺乏专业的后端开发人员&#xff0c;比如&#xff1a; &#xff08;1&#xff09;数据库表已…

PHP开发日志 ━━ 基于PHP和JS的AES相互加密解密方法详解(CryptoJS) 适合CryptoJS4.0和PHP8.0

最近客户在做安全等保&#xff0c;需要后台登录密码采用加密方式&#xff0c;原来用个base64变形一下就算了&#xff0c;现在不行&#xff0c;一定要加密加key加盐~~ 前端使用Cypto-JS加密&#xff0c;传输给后端使用PHP解密&#xff0c;当然&#xff0c;前端虽然有key有盐&…

如何学习计算机编程?零基础入门,轻松成为编程达人!

在这个信息爆炸的时代&#xff0c;计算机编程已经成为一项炙手可热的技能。如果你也对编程充满兴趣&#xff0c;但又不知从何入手&#xff0c;那么本文将为你提供一条通往编程世界的捷径。掌握了这些技巧&#xff0c;相信你一定能够轻松成为编程达人&#xff01; 一、选择合适…

lag-llama源码解读(Lag-Llama: Towards Foundation Models for Time Series Forecasting)

Lag-Llama: Towards Foundation Models for Time Series Forecasting 文章内容&#xff1a; 时间序列预测任务&#xff0c;单变量预测单变量&#xff0c;基于Llama大模型&#xff0c;在zero-shot场景下模型表现优异。创新点&#xff0c;引入滞后特征作为协变量来进行预测。 获得…

爬虫工作量由小到大的思维转变---<第三十五章 Scrapy 的scrapyd+Gerapy 部署爬虫项目>

前言: 项目框架没有问题大家布好了的话,接着我们就开始部署scrapy项目(没搭好架子的话,看我上文爬虫工作量由小到大的思维转变---&#xff1c;第三十四章 Scrapy 的部署scrapydGerapy&#xff1e;-CSDN博客) 正文: 1.创建主机: 首先gerapy的架子,就相当于部署服务器上的;所以…

Ubuntu 18.04搭建RISCV和QEMU环境

前言 因为公司项目代码需要在RISCV环境下测试&#xff0c;因为没有硬件实体&#xff0c;所以在Ubuntu 18.04上搭建了riscv-gnu-toolchain QEMU模拟器环境。 安装riscv-gnu-toolchain riscv-gnu-toolchain可以从GitHub上下载源码编译&#xff0c;地址为&#xff1a;https://…

大华主动注册协议介绍

一、大华主动注册协议介绍 前面写了一篇文章&#xff0c;介绍一些设备通过大华主动注册协议接入到AS-V1000的文章&#xff0c;很多问我关于大华主动注册协议的相关知识。 由于大华主动注册协议是一种私有协议&#xff0c;通常不对外公开详细的协议规范和技术细节。因此…

C++ Primer Plus----第十二章--类和动态内存分布

本章内容包括&#xff1a;对类成员使用动态内存分配&#xff1b;隐式和显式复制构造函数&#xff1b;隐式和显式重载赋值运算符&#xff1b;在构造函数中使用new所必须完成的工作&#xff1b;使用静态类成员&#xff1b;将定位new运算符用于对象&#xff1b;使用指向对象的指针…

ssm基于web的志愿者管理系统的设计与实现+vue论文

摘 要 使用旧方法对志愿者管理系统的信息进行系统化管理已经不再让人们信赖了&#xff0c;把现在的网络信息技术运用在志愿者管理系统的管理上面可以解决许多信息管理上面的难题&#xff0c;比如处理数据时间很长&#xff0c;数据存在错误不能及时纠正等问题。这次开发的志愿者…

【常用前端框架总结】

React.js React.js是由Facebook开发的一个用于构建用户界面的JavaScript库。它采用组件化的开发方式&#xff0c;使得构建复杂的用户界面变得更加简单和可维护。React.js使用虚拟DOM技术来高效地更新界面&#xff0c;并具有强大的生态系统&#xff0c;包括大量的第三方库和工具…

main参数传递、反汇编、汇编混合编程

week03 一、main参数传递二、反汇编三、汇编混合编程 一、main参数传递 参考 http://www.cnblogs.com/rocedu/p/6766748.html#SECCLA 在Linux下完成“求命令行传入整数参数的和” 注意C中main: int main(int argc, char *argv[]), 字符串“12” 转为12&#xff0c;可以调用atoi…

二、C#基础语法( 异常处理)

在C#中&#xff0c;异常处理是一种处理程序运行时可能出现的错误或异常情况的重要机制。通过异常处理&#xff0c;我们可以捕获并处理程序中的错误&#xff0c;从而避免程序崩溃或产生不可预测的行为。 C#中的异常处理主要通过try-catch语句块来实现。以下是C#中异常处理的基础…

两种汇编的实验

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. 删除汇编代码…

思维逻辑题3

题目1&#xff1a; 如果所有A都是B&#xff0c;且某个对象是B&#xff0c;那么它一定是A吗&#xff1f; 答案&#xff1a;不一定&#xff0c;尽管所有A都是B&#xff0c;但还有其他的对象可能也是B。 题目2&#xff1a; 如果A和B都是真&#xff0c;那么以下哪个选项是真&…

自身文档管理规范

之前在 这里 叙述了 用 sphinx 生成静态网站&#xff0c; 并利用 静态网络托管服务 readthedocs 现在我们有了新的需求&#xff0c;想知道这些东西到底是什么。 过程 过程A &#xff1a; markdown/rst -> html mkdocs sphinx相关&#xff1a; pandoc(不能生成整个网站的h…

vue中的一个内置组件Keep-Alive的作用及使用方法介绍——缓存不活动的组件实例

一、什么是 keep-alive 在平常开发中&#xff0c;有部分组件没有必要多次初始化&#xff0c;这时&#xff0c;我们需要将组件进行持久化&#xff0c;使组件的状态维持不变&#xff0c;在下一次展示时&#xff0c;也不会进行重新初始化组件。 Keep-Alive是Vue.js中的一个内置组…

expdp到ASM 文件系统 并拷贝

1.创建asm导出数据目录 sql>select name,total_mb,free_mb from v$asm_diskgroup; 确认集群asm磁盘组环境 asmcmd>cd DGDSDB asmcmd>mkdir dpbak asmcmd>ls -l sql>conn / as sysdba create directory expdp_asm_dir as DGDSDB/dpbak; create directory expdp_l…

『番外篇六』SwiftUI 取得任意视图全局位置的三种方法

概览 在 SwiftUI 开发中,利用描述性代码我们可以很轻松的构建各种丰富多彩的视图。我们可以设置它们的大小、位置、颜色并应用不计其数的修改器。 但是,小伙伴们是否想过在 SwiftUI 中如何获取一个视图的全局位置坐标呢? 在本篇博文中,您将学到如下内容: 概览1. SwiftU…

批处理学习笔记1_命令的语法与功能A

批处理除了可以用Windows自带的记事本编辑外&#xff0c;还可以在命令行中输入copy con 文件名来创建&#xff0c;比如&#xff1a;copy con a.bat&#xff0c;然后就可以在命令中编辑&#xff0c;等文件编辑完毕后&#xff0c;输入CTRLz&#xff0c;再敲回车&#xff0c;就可以…

守护 C 盘,Python 相关库设置

文章目录 前言Python 相关查看所有 Python 安装位置查看 Python 依赖位置查看 conda 配置查看 env 列表移除指定 env创建 env进入 env删除环境位置目录添加环境位置 (将位置置顶)查看 pip 缓存位置设置 pip 缓存位置 其他进入 Temp修改位置 Python技术资源分享1、Python所有方向…