当前位置: 首页 > news >正文

初阶数据结构:二叉树

目录

  • 1. 树的相关概念
    • 1.1 简述:树
    • 1.2 树的概念补充
  • 2. 二叉树
    • 2.1 二叉树的概念
    • 2.2 二叉树的性质
    • 2.3 二叉树的存储结构与堆
      • 2.3.1 存储结构
      • 2.3.2 堆的概念
      • 2.3.3 堆的实现
        • 2.3.3.1 堆的向上调整法
        • 2.3.3.2 堆的向下调整算法
        • 2.3.3.3 堆的实现

1. 树的相关概念

1.1 简述:树

树是一种非线性的数据结构,其有n个有限的节点构成,树结构具有层次性。它的形状颇像一颗颠倒的树,因此而被称为树。

补充:

  1. 树的结构中有一个特殊的结点,其没有前驱结点,被称为根结点。
  2. 树的结构中,其子树间不能存在交集,若存在交集,那么,此结构就不能被称为树结构。

1.2 树的概念补充

在这里插入图片描述

  1. 节点的度:一个节点含有的子树的个数称为该节点的度;(A结点的度为3)
  2. 叶子节点:度为0的结点;(E, F, G, D, H结点)
  3. 非叶子节点:度不为0的结点(B,C, G结点)
  4. 父亲节点:若一个节点含有子节点,则这个节点称为其子节点的父节点
  5. 子节点:一个节点含有的子树的根节点称为该节点的子节点;
  6. 兄弟节点:具有相同父节点的节点互称为兄弟节点;
  7. 树的度:一棵树中,最大的节点的度称为树的度;
  8. 节点的层 :从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
  9. 树的深度 :树中节点的最大层次;
  10. 堂兄弟结点 :双亲在同一层的节点互为堂兄弟;
  11. 祖先结点:从根到该节点所经分支上的所有节点;
  12. 子孙结点 :以某节点为根的子树中任一节点都称为该节点的子孙;
  13. 森林: 多棵互不相交的树的集合

2. 二叉树

2.1 二叉树的概念

对于树结构的初次学习,我们来重点学习二叉树这一结构。

在这里插入图片描述

由上图可知,二叉树具有两个特点:

  1. 二叉树是一个结点的集合,可能为空或者由根节点,左子树,右子树构成。
  2. 二叉树由左右子树之分,所以,二叉树为一个有序树,其顺序不能颠倒。
  3. 二叉树的没有拥有超过两个孩子结点的结点,即二叉树的度为2
  4. 补充:特殊的二叉树
    <1> 满二叉树:除叶子结点外,所有结点都有左右孩子结点,若k二叉树的层数,那么满二叉树的结点就有 k 2 k^2 k2 - 1个结点。
    <2> 完全二叉树:除最后一层外,所有结点都有左右孩子结点,最后一层叶子结点连续

在这里插入图片描述

2.2 二叉树的性质

  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i - 1) 个结点.
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是 2 h 2^h 2h - 1.(等比数列求和)
  3. 任何一棵二叉树, 如果度为0其叶结点个数为n, 则其度为0的结点一定比度为2的结点多一个.
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h = l o g 2 ( n + 1 ) log_2(n + 1) log2(n+1)
  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
    <1> 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
    <2> 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
    <3> 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

2.3 二叉树的存储结构与堆

2.3.1 存储结构

  1. 顺序存储:
    其采用的方式为使用数组进行数据的存储,其各个结点的关系通过下标之间的数学关系来实现,在物理结构上其仍为数组,此结构只适合存储完全二叉树。
  2. 链式存储:
    使用链表的方式来存储数据,其存在三个域,数据域,左孩子指针域,右孩子指针域。在逻辑上,呈现链式的逻辑结构。

2.3.2 堆的概念

  1. 堆是一棵完全二叉树。
  2. 堆分为大堆与小堆,当所有结点的值都大于孩子结点时即为大堆,当所有结点的值都小于其孩子结点时即为小堆。

2.3.3 堆的实现

  1. 因为堆都是完全二叉树,这里我们使用顺序存储的方式来进行堆的实现。
  2. 在数组中若父亲节点的下标为pos,其左孩子的下标为pos × 2 + 1,右孩子结点的下标为pos × 2 + 2,下标为0的元素为根结点。(顺序存储方式,使用数组来实现堆结构的方式)

在这里插入图片描述

我们已经知晓了如何判断一个数组是否为堆,可我们对下面两个问题还是没有办法去解决:

  1. 当一个数组是堆时,我们如何保证在不断向数组中插入数据而堆的结构不被打乱。
  2. 如何将一个不是堆的数组调整为堆。
  3. 如何去创建一个是堆的数组。

我们接下来进行这几个问题的学习。

2.3.3.1 堆的向上调整法

在这里插入图片描述

void HeapAdjustUp(int* arr, int child)
{int parent = (child - 1) / 2;while (child > 0){if (arr[parent] < arr[child]){swap(&arr[parent], &arr[child]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

向上调整建堆

  1. 将数组中的元素从首元素开始一个一个视作插入已有的堆中在进行向上调整,初始堆为空。

那么,我们就可以进行如下操作:

for(int i = 0; i < n; i++)
{HeapAdjustUp(arr, i);
}
2.3.3.2 堆的向下调整算法
void HeapAdjustDown(int* arr, int n, int parent)
{//n为元素个数int child = parent * 2 + 1;while (child < n){if (child + 1 < n && arr[child] < arr[child + 1]){child++;}if (arr[parent] < arr[child]){swap(&arr[parent], &arr[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}

向下调整法建堆
2. 我们从最后一个非叶子结点开始,向下调整,调整过后的子树都为堆,一直循环到根结点。

操作如下:

过程演示:
在这里插入图片描述

for (int j = (n - 1 - 1) / 2; j >= 0; j--)
{HeapAdjustDown(arr, n, j);
}
2.3.3.3 堆的实现

堆的结构:

typedef struct Heap
{int* data;int size;int capacity;
}Heap;

堆的初始化与销毁:

void HeapInit(Heap* heap)
{heap->data = NULL;heap->capacity = heap->size = 0;
}void HeapDestroy(Heap* heap)
{while (heap->size){HeapPop(heap);}free(heap->data);heap->data = NULL;heap->capacity = heap->size = 0;
}

堆的元素增加与头删

void CheckCapacity(Heap* heap)
{if (heap->size == heap->capacity){int newcapacity = heap->capacity == 0 ? 4 : heap->capacity * 2;int* tmp = (int*)realloc(heap->data, newcapacity * sizeof(int));if (tmp == NULL){perror("malloc failed");exit(-1);}heap->data = tmp;heap->capacity = newcapacity;}
}void HeapPush(Heap* heap, int val)
{CheckCapacity(heap);heap->data[heap->size] = val;heap->size++;HeapAdjustUp(heap->data, heap->size - 1);
}//逆置首尾元素,size--,再向下调整
//向下调整后堆仍为堆的前置条件为,左右子树都为堆
void HeapPop(Heap* heap)
{assert(!HeapEmpty(heap));swap(&heap->data[0], &heap->data[heap->size - 1]);heap->size--;//左右子树都为堆HeapAdjustDown(heap->data, heap->size, 0);
}

返回堆顶元素与判空:

bool HeapEmpty(Heap* heap)
{return heap->size == 0;
}int HeapTop(Heap* heap)
{assert(!HeapEmpty(heap));return heap->data[0];
}

相关文章:

  • langchain学习笔记(十)
  • SMBGhost漏洞技术分析与防御方案
  • 【C++干货基地】揭秘C++11常用特性:内联函数 | 范围for | auto自动识别 | nullptr指针空值
  • 向日葵、Todesk、teamviewer等工具远程连接电脑时第三方应用显示白屏
  • 编程笔记 Golang基础 045 math包
  • chrome选项页面options page配置
  • AI网址啊
  • 【css面试题】BFC
  • 通过QScrollArea寻找最后一个弹簧并且设置弹簧大小
  • OpenCV 4基础篇| OpenCV图像的裁切
  • leetcode移除元素
  • AzerothCore安装记录
  • UniApp项目处理小程序分包
  • HarmonyOS 开发之———应用程序入口—UIAbility的使用
  • Java学习--学生管理系统(残破版)
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • const let
  • Git同步原始仓库到Fork仓库中
  • HTTP请求重发
  • Koa2 之文件上传下载
  • PHP CLI应用的调试原理
  • uni-app项目数字滚动
  • 好的网址,关于.net 4.0 ,vs 2010
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 一、python与pycharm的安装
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (js)循环条件满足时终止循环
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (规划)24届春招和25届暑假实习路线准备规划
  • (五)Python 垃圾回收机制
  • (一)Thymeleaf用法——Thymeleaf简介
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • .net core 源码_ASP.NET Core之Identity源码学习
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .net6Api后台+uniapp导出Excel
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .NET成年了,然后呢?
  • /ThinkPHP/Library/Think/Storage/Driver/File.class.php  LINE: 48
  • [100天算法】-二叉树剪枝(day 48)
  • [C]整形提升(转载)
  • [C++]拼图游戏
  • [CC2642R1][VSCODE+Embedded IDE+IAR Build+Cortex-Debug] TI CC2642R1基于VsCode的开发环境
  • [CUDA 学习笔记] CUDA kernel 的 grid_size 和 block_size 选择
  • [C语言][PTA基础C基础题目集] strtok 函数的理解与应用
  • [docker] Docker的私有仓库部署——Harbor
  • [HTML]Web前端开发技术18(HTML5、CSS3、JavaScript )HTML5 基础与CSS3 应用——喵喵画网页
  • [Java]快速入门优先队列(堆)手撕相关面试题
  • [NAND Flash 6.1] 怎么看时序图 | 从时序理解嵌入式 NAND Read 源码实现
  • [nlp] tokenizer
  • [PHP]关联和操作MySQL数据库然后将数据库部署到ECS