数据结构之顺序结构二叉树(超详解)


文章目录
- 1 树
- 1.1 树的概念与结构
- 1.2 相关术语
- 1.3 树的表示与运用场景
- 1.3.1 运用场景
- 2. 二叉树
- 2.1 概念与结构
- 2.1.1 满二叉树
- 2.1.2 完全二叉树
- 3. 顺序结构二叉树
- 3.1 堆的引入
- 3.1.1 概念与结构
- 3.2 功能实现
- 3.2.1 堆的结构
- 3.2.2 初始化、销毁
- 3.3 堆的插入数据
- 3.3.1 向上调整算法
- 3.4 堆是否为空
- 3.5 删除堆顶数据
- 3.5.1 向下调整算法
- 3.5.2 获取堆顶数据
- 3.5.2.1 求有效数据个数
- 3.6 向上(下)调整算法的复杂度比较
- 3.6.1 向上调整算法时间复杂度
- 3.6.2 向下调整算法时间复杂度
- 4. 代码实现
1 树
1.1 树的概念与结构
树是⼀种非线性的数据结构,它是由 n(n>=0) 个有限结点组成⼀个具有层次关系的集合。
具有以下特点:
- 具有根节点,且根节点无前驱结点。
- 除根结点外,其余结点被分成 M(M>0) 个互不相交的集合,每⼀个集合又是⼀棵结构与树类似的子树。每棵子树的根结点仅有一个前驱结点,但可以有多个互不相交的后驱结点。(若存在相交就是图了)

1.2 相关术语
- 子结点/孩子结点:⼀个结点的子树的根结点称子结点; 如上图:B是A的子结点。
- 父结点/双亲结点:含有子结点的结点称为其子结点的父结点; 如上图:A是B的父结点。
- 结点的度:⼀个结点有几个子结点,度就是多少;如A的度为3,F的度为0。
- 树的度:⼀棵树中,最大的结点的度称为树的度; 如上图:树的度为3。
- 叶子结点/终端结点:度为 0 的结点称为叶结点; 如上图: J、K、L… 等结点为叶结点。
- 分支结点/非终端结点:度不为 0 的结点; 如上图: A、B、C、D… 等结点为分支结点。
- 兄弟结点:具有相同父结点的结点互称为兄弟结点(亲兄弟); 如上图: E、F 是兄弟结点。
- 结点的层次:从根开始定义起,根为第 1 层,根的⼦结点为第 2 层,以此类推。
- 树的高度或深度:树中结点的最大层次; 如上图:树的高度为 4。
- 结点的祖先:从根到该结点所经分支上的所有结点;如上图: A 是所有结点的祖先。
- 子孙:以某结点为根的子树中任⼀结点都称为该结点的子孙。如上图:所有结点都是A的子孙
- 路径:⼀条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列;如A到J的路径为:A-B-E-J。
- 森林:由 m(m>0) 棵互不相交的树的集合称为森林。
1.3 树的表示与运用场景
树的表示有很多种,最常用的便是孩子兄弟表示法,其很好地解决了结点和结点之间的关系。
struct TreeNode
{struct Node* child; // 左边开始的第⼀个孩⼦结点struct Node* brother; // 指向其右边的下⼀个兄弟结点int data; // 结点中的数据域
};

1.3.1 运用场景
文件系统是计算机存储和管理文件的⼀种方式,它利用树形结构来组织和管理文件和文件夹。在文件系统中,树结构被广泛应用,它通过父结点和⼦结点之间的关系来表示不同层级的文件和文件夹之间的关联。

2. 二叉树
2.1 概念与结构
⼀棵二叉树是结点的⼀个有限集合,该集合由⼀个根结点加上两棵别称为左子树和右子树的二叉树组成或者为空。

特点:
- 不存在大于度大于2的结点;
- 二叉树有左右之分,次序不能颠倒。
2.1.1 满二叉树
如果每⼀个层的结点数都达到最大值或满足结点总数是2k-1则这个二叉树就是满二叉树。
2k-1的公式推导:

总的结点数:20 + 21 + 22+……+2k-1 = 1 * (1 - 2k) / 1 - 2 = 2k-1
2.1.2 完全二叉树
规定根结点的层数为 1:
- ⼀棵非空二叉树的第i层上最多有 2i−1 个结点
- 深度为 h 的二叉树的最大结点数是 2h − 1
- 具有 n 个结点的满二叉树的深度 h = log2 (n + 1) ( log以2为底, n+1 为对数) -->满二叉树是特殊的完全二叉树。
3. 顺序结构二叉树
顺序结构存储是使用数组来存储,在实现完全二叉树能减少空间浪费。

3.1 堆的引入
3.1.1 概念与结构


- 对于序号i对应的结点,若i>0,则(i-1)/2为父结点;若i=0,则无父结点;
- 若2*i+1<n,则对应其左孩子;
- 若2*i+2<n,则对应其右孩子。
3.2 功能实现
3.2.1 堆的结构
由于堆底层是用数组实现的,因此相似于顺序表,其结构定义如下:
typedef int HPDataType;
//定义堆的结构
typedef struct HeapNode
{HPDataType* arr;int size;//有效数据个数int capacity;//容量
}HP;
3.2.2 初始化、销毁
这些代码实现已经在顺序表中介绍到。
//堆的初始化
void HPInit(HP* php)
{assert(php);php->arr = NULL;php->size = php->capacity = 0;
}
//堆的销毁
void HPDesTroy(HP* php)
{assert(php);if (php->arr)free(php->arr);php->arr = NULL;php->capacity = php->size = 0;
}
3.3 堆的插入数据
熟悉了堆的概念与结构后,我们清楚堆要不就是大根堆,要不就是小根堆。问题在于插入数据后,我们如何通过代码实现化成大根堆或者小根堆的形式?由此我们提出了向上(下)调整算法,也会带大家分析这两种算法哪种更好。

3.3.1 向上调整算法


3.4 堆是否为空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}
3.5 删除堆顶数据
- 在删除堆顶数据时,先要判断堆是否为空,因此采用assert。
- 删除堆顶数据后,如何让其再次成为大(小)根堆。

由此我们引入了向下调整算法。
3.5.1 向下调整算法
前提:左右⼦树必须是⼀个堆,才能调整。

3.5.2 获取堆顶数据
HPDataType HPTop(HP* php)
{assert(!HPEmpty(php));return php->arr[0];
}
3.5.2.1 求有效数据个数
int HPSize(HP* php)
{assert(php);return php->size;
}
3.6 向上(下)调整算法的复杂度比较
3.6.1 向上调整算法时间复杂度

根据大O表示法,则O(n*log2n) --> 详见算法复杂度篇章
3.6.2 向下调整算法时间复杂度

根据大O表示法可见时间复杂度为O(n)
因此==向下调整算法的时间复杂度更优==。
4. 代码实现
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<time.h>typedef int HPDataType;
//定义堆的结构
typedef struct HeapNode
{HPDataType* arr;int size;//有效数据个数int capacity;//容量
}HP;//堆的初始化
void HPInit(HP* php);
//堆的销毁
void HPDesTroy(HP* php);
//堆的插入数据
void HPPush(HP* php, HPDataType x);
//删除堆顶数据
void HPPop(HP* php);
//获取堆顶数据
HPDataType HPTop(HP* php);
//判空
bool HPEmpty(HP* php);
//求size
int HPSize(HP* php);//向上调整
void AdjustUp(HPDataType* arr, int child);
//向下调整
void AdjustDown(HPDataType* arr, int parent, int n);
//交换
void Swap(int* x, int* y);
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"//堆的初始化
void HPInit(HP* php)
{assert(php);php->arr = NULL;php->size = php->capacity = 0;
}
//堆的销毁
void HPDesTroy(HP* php)
{assert(php);if (php->arr)free(php->arr);php->arr = NULL;php->capacity = php->size = 0;
}
//交换
void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
//向上调整
void AdjustUp(HPDataType* arr, int child)
{int parent = (child - 1) / 2;while (child > 0){//>:大堆//<:小堆if (arr[child] > arr[parent]){//交换Swap(&arr[child], &arr[parent]);child = parent;parent = (child - 1) / 2;}else {break;}}
}
//堆的插入数据
void HPPush(HP* php, HPDataType x)
{assert(php);//判断空间是否不足if (php->size == php->capacity){int newCapacity = php->capacity == 0 ? 4 : 2 * php->capacity;//空间不足需要增容HPDataType* tmp = (HPDataType*)realloc(php->arr, sizeof(HPDataType) * newCapacity);if (tmp == NULL){perror("realloc fail!");exit(1);}//realloc成功php->arr = tmp;php->capacity = newCapacity;}php->arr[php->size] = x;//向上调整AdjustUp(php->arr, php->size - 1);php->size++;
}//向下调整
void AdjustDown(HPDataType* arr, int parent, int 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;}}
}
//删除堆顶数据
void HPPop(HP* php)
{assert(!HPEmpty(php));Swap(&php->arr[0], &php->arr[php->size - 1]);php->size--;//向下调整AdjustDown(php->arr, 0, php->size);
}
//获取堆顶数据
HPDataType HPTop(HP* php)
{assert(!HPEmpty(php));return php->arr[0];
}
//判空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}
//求size
int HPSize(HP* php)
{assert(php);return php->size;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"void test()
{HP hp;HPInit(&hp);HPPush(&hp, 1);HPPush(&hp, 3);HPPush(&hp, 2);HPPush(&hp, 4);/*HPPop(&hp);HPPop(&hp);HPPop(&hp);HPPop(&hp);*/while (!HPEmpty(&hp)){printf("%d ", HPTop(&hp));HPPop(&hp);}HPDesTroy(&hp);
}void test01()
{int arr[] = { 14,51,31,21,23,32 };int n = sizeof(arr) / sizeof(arr[0]);HP hp;HPInit(&hp);//调用push将数组中的数据建堆for (int i = 0;i < n;i++){HPPush(&hp, arr[i]);}int i = 0;while (!HPEmpty(&hp)){arr[i++] = HPTop(&hp);HPPop(&hp);}for (int i = 0;i < n;i++){printf("%d ", arr[i]);}HPDesTroy(&hp);
}int main()
{test();test01();//int arr[] = { 14,51,31,21,23,32 };//int n = sizeof(arr) / sizeof(arr[0]);Bubblesort(arr,n);//HeapSort(arr,n);//for (int i = 0;i < n;i++)//{// printf("%d ", arr[i]);//}//CreateDate();TopK();return 0;
}


相关文章:
数据结构之顺序结构二叉树(超详解)
文章目录 1 树1.1 树的概念与结构1.2 相关术语1.3 树的表示与运用场景1.3.1 运用场景 2. 二叉树2.1 概念与结构2.1.1 满二叉树2.1.2 完全二叉树 3. 顺序结构二叉树3.1 堆的引入3.1.1 概念与结构 3.2 功能实现3.2.1 堆的结构3.2.2 初始化、销毁 3.3 堆的插入数据3.3.1 向上调整算…...
acwing_5722_十滴水
acwing_5722_十滴水 下面这篇大佬的题解属实是把指针用明白了,可以好好理解一下: 原题解连接:AcWing 5722. 一个简单模拟实现 - AcWing map/unordered_map的用法:见收藏夹 #include<iostream> #include<unordered_map> #incl…...
acwing-3194 最大的矩形
acwing-3194 最大的矩形 这个题程序设计课上有讲过, 平民算法,时间复杂度在 O ( n 2 ) O(n^2) O(n2) // // Created by HUAWEI on 2024/10/28. // #include<iostream>using namespace std;const int Max_size 1e4 20;int N; int h[Max_size];…...
UnityDemo-TheBrave-制作笔记
这是我跟着b站up主MStudio的视频学习制作的,大体上没有去做一些更新的东西,这里只是一个总的总结。在文章的最后,我会放上可以游玩该游戏的链接和exe可执行文件,不过没有对游戏内容进行什么加工,只有基本的功能实现罢了…...
玩转 JMeter:Random Order Controller让测试“乱”出花样
嘿,各位性能测试的小伙伴们!今天咱要来唠唠 JMeter 里超级有趣又超实用的 Random Order Controller(随机顺序控制器),它就像是性能测试这场大戏里的“魔术棒”,轻轻一挥,就能让测试场景变得千变…...
VTK知识学习(33)-交互问题2
1、前言 主要是针对前面有过实现不了交互的情况进行说明,经过一些尝试和分析调用API,总算实现RenderWindowControl函数回调正常串接,当然这个移动处理事件的效果目前也没有确认。 2、使用 vtkImageReslice reslice vtkImageReslice.New();p…...
Centos9-SSH免密登录配置-修改22端口-关闭密码登录-提高安全性
Centos9-SSH免密登录配置-修改22端口-关闭密码登录 生成秘钥对将公钥信息存进authorized_keys测试登录查询访问记录、比对指纹更换22访问端口关闭账号密码登录生成秘钥对 生成密钥对,指定 备注 和 文件目录命令执行后,默认两次回车,不设置秘钥使用密码ssh-keygen -t rsa -b …...
SqlServer: An expression services limit has been reached异常处理
在工作中遇到一个问题,因为项目很老,代码很不规范,出现一种场景: 查询所有客户(5w条以上),然后根据客户Id,再去其他表查询,代码中是直接将customerId拼接到sql中去查询,形成的sql如…...
CentOS下安装Docker
Docker 必须要在Linux环境下才能运行,windows下运行也是安装虚拟机后才能下载安装运行,菜鸟教程 下载安装 linux 依次执行下边步骤 更新 yum yum update 卸载旧的Docker yum remove docker docker-client docker-client-latest docker-common doc…...
WPF控件Grid的布局和C1FlexGrid的多选应用
使用 Grid.Column和Grid.Row布局,将多个C1FlexGrid布局其中,使用各种事件来达到所需效果,点击复选框可以加载数据到列表,移除列表的数据,自动取消复选框等 移除复选框的要注意!!!&am…...
Jenkins-持续集成、交付、构建、部署、测试
Jenkins-持续集成、交付、构建、部署、测试 一: Jenkins 介绍1> Jenkins 概念2> Jenkins 目的3> Jenkins 特性4> Jenkins 作用 二:Jenkins 版本三:DevOps流程简述1> 持续集成(Continuous Integration,CI࿰…...
高级第一次作业
1、shell 脚本写出检测 /tmp/size.log 文件如果存在显示它的内容,不存在则创建一个文件将创建时间写入。 2、写一个 shel1 脚本,实现批量添加 20个用户,用户名为user01-20,密码为user 后面跟5个随机字符。 3、编写个shel 脚本将/usr/local 日录下大于10M的文件转移到…...
Copula算法原理和R语言股市收益率相依性可视化分析
阅读全文:http://tecdat.cn/?p6193 copula是将多变量分布函数与其边缘分布函数耦合的函数,通常称为边缘。在本视频中,我们通过可视化的方式直观地介绍了Copula函数,并通过R软件应用于金融时间序列数据来理解它(点击文…...
反弹SHELL不回显带外正反向连接防火墙出入站文件下载
什么是反弹shell 正向连接正向连接(Forward Connection):正向连接是一种常见的网络通信模式,其中客户端主动发起连接到服务器或目标系统。正向连接通常用于客户端-服务器通信,客户端主动请求服务或资源,例如…...
后盾人JS--JS值类型使用
章节介绍与类型判断 看看构造函数 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</t…...
1月11日
[WUSTCTF2020]CV Maker 可以看到有个注册页面,尝试注册一个用户登进去看看 进来后第一眼就看到文件上传,尝试上传,上传php后返回了 文件上传后端检测exif_imagetype()函数 他提示不是image,也就是需要我们构造一个文件头为图像类…...
【深度学习】Pytorch:加载自定义数据集
本教程将使用 flower_photos 数据集演示如何在 PyTorch 中加载和导入自定义数据集。该数据集包含不同花种的图像,每种花的图像存储在以花名命名的子文件夹中。我们将深入讲解每个函数和对象的使用方法,使读者能够推广应用到其他数据集任务中。 flower_ph…...
最近在盘gitlab.0.先review了一下docker
# 正文 本猿所在产品的代码是保存到了一个本地gitlab实例上,实例是别的同事搭建的。最近又又又想了解一下,而且已经盘了一些了,所以写写记录一下。因为这个事儿没太多的进度压力,索性写到哪儿算哪儿,只要是新了解到的…...
OA项目登录
导入依赖,下面的依赖是在这次OA登录中用到的 <!--web依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.sprin…...
verilogHDL仿真详解
前言 Verilog HDL中提供了丰富的系统任务和系统函数,用于对仿真环境、文件操作、时间控制等进行操作。(后续会进行补充) 正文 一、verilogHDL仿真详解 timescale 1ns/1ps //时间单位为1ns,精度为1ps, //编译…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
如何配置一个sql server使得其它用户可以通过excel odbc获取数据
要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据,你需要完成以下配置步骤: ✅ 一、在 SQL Server 端配置(服务器设置) 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到:SQL Server 网络配…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...
车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...
