数据结构-----平衡二叉树
目录
前言
1.平衡二叉树
1.1概念与特点
1.2与二叉排序树比较
1.3判断平衡二叉树
2.平衡二叉树的构建
2.1平衡因子 BF
2.2 LL型失衡(右旋)
2.3 RR型失衡(左旋)
2.4 LR型失衡(先左旋再右旋)
2.5 RL型失衡(先右旋再左旋)
2.6构建平衡二叉树代码实现
3.删除节点操作
3.1删除叶子节点
3.2删除只有一个左(右)子树的节点
3.3删除有左右子树的节点
3.4删除节点代码实现
4.平衡二叉树相关操作
4.1查找数据
4.2判断是否为平衡二叉树
4.3中序遍历输出
4.4销毁平衡二叉树
前言
前面我发布了一篇介绍二叉排序树的相关文章,那么今天我们学习一种新的树----平衡二叉树,在此之前我们要学习过二叉排序树,才能更好的去学习平衡二叉树,平衡二叉树是二叉排序树的进一步优化,下面就一起来看看吧!
1.平衡二叉树
1.1概念与特点
在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。
二叉排序树相关链接:数据结构-----二叉排序树_Gretel Tade的博客-CSDN博客
特性:
- 平衡二叉树是一个二叉排序树
- 它的左子树和右子树都是平衡二叉树
- 左右子树高度之差(简称平衡因子)的绝对值不超过 1(即:-1,0,1)
如图所示:
1.2与二叉排序树比较
在此之前我们学习过了二叉排序树的相关知识点,二叉排序树又名为二叉搜索树,但是当一个二叉排序树的形态是一个链状的话,那么搜索效率跟一个链表的搜索效率是毫无区别的,但是如果是一个平衡二叉树就不同了,因为平衡二叉树规定了左右子树高度差不会大于1,这样就可以大大提高了搜索的效率,下面看比较:
当前我插入[1,2,3,4,5,6] 这一数组构建一个二叉排序树的时候,其形态是如下图所示,很明显是一个链态的,无异于一个链表,当我要去搜索数字6的时候,就要遍历到最后一个数字,搜索效率为 O(n)。
但是如果我通过构建平衡二叉树来储存这些数据的话,那就会有很大的不同,如下图所示,当我要去搜索最后一个节点的时候,就不需要去遍历这么多节点了,可以这么说,平衡二叉树是排序二叉树的优化结果。
1.3判断平衡二叉树
- 1. 是二叉排序树
- 2. 任何一个节点的左子树或者右子树都是平衡二叉树,而且左右高度差小于等于 1
(1)这个不是平衡二叉树, 因为右子树比左子树高度差大于2
(2)这个不是平衡二叉树,因为没有符合二叉排序树的要求
(3)这个是平衡二叉树,既满足二叉排序树的要求,而且左右子树高度差小于2.
2.平衡二叉树的构建
前面去构建一个二叉排序树,非常简单,只需要排序就行了,那构建一个平衡二叉树不仅仅要考虑到排序问题,还要考虑到左右子树高度不大于1才行,下面我介绍一种通过旋转的方法来去构建平衡二叉树。
2.1平衡因子 BF
定义:左子树和右子树高度差
计算方法:左子树高度减右子树高度的绝对值
当满足BF<=1的时候,这个树就满足平衡条件。当不满足平衡条件的话,那就只能去通过旋转来实现平衡。下面有4种不满足平衡条件的情况,如图所示:
树1是满足平衡条件的情况;
树2是在左子树右子节点出现失衡情况,属于 LR型
树3是在右子树右子节点出现失衡情况,属于 RR型
树4是在左子树左子节点出现失衡情况,属于 LL型
树5是在右子树左子节点出现失衡情况,属于 LR型
下面我就一一讲解怎么去通过旋转来处理上面这四种失衡问题。
2.2 LL型失衡(右旋)
右旋就是通过顺时针旋转来实现平衡,就是处于右边的根结点落下变为叶子节点,而中间的节点变为新的根节点,最左边的叶子节点保持不变,最后形成新的结构。
动图演示:
2.3 RR型失衡(左旋)
对于RR型失衡,通过逆时针旋转,最左边的根结点落下,变成叶子节点,中间的节点变为新的根节点,最右边的叶子节点保持不变。
动图演示:
2.4 LR型失衡(先左旋再右旋)
对于LR型失衡,先在根节点左子树进行左旋处理,变成LL型失衡,然后再去通过右旋来实现整体平衡。动图演示如下:
先左旋:
再右旋:
2.5 RL型失衡(先右旋再左旋)
对于RL型失衡,在根节点的右子树先进行右旋处理,形成RR型失衡,然后整体进行左旋处理,最后达到平衡状态,动态演示如下:
先右旋:
再左旋:
2.6构建平衡二叉树代码实现
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int Datatype;
typedef struct AVLtree {Datatype data;int heigh;//高度struct AVLtree* left;struct AVLtree* right;
}Node;//绝对值
int abs(int a, int b) {return a - b > 0 ? a - b : b - a;
}//创建一个节点
Node* Create_node(Datatype data) {Node* new_node = (Node*)malloc(sizeof(Node));if (!new_node) {printf("ERROR\n");exit(-1);}new_node->data = data;new_node->left = new_node->right = NULL;new_node->heigh = 0;return new_node;
}//获取高度
int get_height(Node* T) {if (!T)return 0;elsereturn T->heigh;
}//1.插入右子树右节点,右旋
void right_rigth(Node** root) {Node* k = (*root)->right;(*root)->right = k->left;k->left = (*root);k->heigh = get_height(k->left) > get_height(k->right) ? get_height(k->left) : get_height(k->right);(*root)->heigh = get_height((*root)->left) > get_height((*root)->right) ? get_height((*root)->left) : get_height((*root)->right);*root = k;
}
//2.插入左子树左节点,失去平衡,左旋
void left_left(Node** root) {Node* k = (*root)->left;(*root)->left = k->right;k->right = (*root);k->heigh = get_height(k->left) > get_height(k->right) ? get_height(k->left) : get_height(k->right);(*root)->heigh = get_height((*root)->left) > get_height((*root)->right) ? get_height((*root)->left) : get_height((*root)->right);*root = k;
}
//3.插入左子树,右节点,失去平衡,先右旋再左旋
void left_right(Node** root) {right_rigth(&((*root)->left));left_left(&(*root));
}
//4.插入右子树左节点,失去平衡,先左旋再右旋
void rigth_left(Node** root) {left_left(&((*root)->right));right_rigth(&(*root));
}//插入节点
void Insert_node(Datatype data, Node** root) {if (!(*root)) {(*root) = Create_node(data);return;}else {if (data < (*root)->data) {Insert_node(data, &((*root)->left));if (get_height((*root)->left) - get_height((*root)->right) > 1) {//如果出现失衡的情况if(data<(*root)->left->data)left_left(&(*root));elseleft_right(&(*root));}}else if (data > (*root)->data) {Insert_node(data, &((*root)->right));if (get_height((*root)->right) - get_height((*root)->left) > 1) {//如果出现失衡的情况if(data>(*root)->right->data)right_rigth(&(*root));elserigth_left(&(*root));}}else {printf("Do not insert numbers of the same size!\n");return;}}(*root)->heigh++;
}//创建平衡二叉树
void Create_AVLtree(Node** T, Datatype* data,int n) {if (!data) {return;}for (int i = 0; i < n; i++) {Insert_node(data[i],T);}
}
3.删除节点操作
在对平衡二叉树进行删除节点的操作时候,跟插入节点也是一样的,会出现失衡的情况,那这里就要通过旋转来去处理了,要进行那种旋转就要根据删除的节点属性去看,以下有4种情况:
- 删除叶子结点
- 删除结点只有左子树
- 删除结点只有右子树
- 删除结点有左、右子树
下面就一个一个来看,怎么去进行删除吧
3.1删除叶子节点
删除叶子节点后要看,平衡二叉树是否失衡,如果没有失衡就直接删除即可;如果出现了失衡的情况就要从根节点开始向上依次检索看从哪个位置开始失衡了,一经发现失衡就进行相对于的旋转处理,直到根结点为止。
3.2删除只有一个左(右)子树的节点
这种情况就要用这个被删除节点的相邻节点来去顶替这个节点,然后整体进行相对于的旋转操作。如下图所示:
3.3删除有左右子树的节点
要删除的节点有左右子树的话,那么就找到左子树的最大节点或者找到右子树最小节点来替换掉这个节点,然后把这个节点的空间释放掉就行了。
3.4删除节点代码实现
//查找数据节点
Node* Search_node(Node *T,Datatype target) {if (!T) {return NULL;}if (target == T->data)return T;else if (target < T->data)Search_node(T->left, target);elseSearch_node(T->right, target);
}//删除指定数据的节点
void Del_node(Node** T, Datatype target) {Node* dnode = Search_node(*T, target);if (!dnode){//如果查找不成功,就返回printf("bye~~~error\n");return;}if (target < (*T)->data) {Del_node(&(*T)->left, target);if (get_height((*T)->left) - get_height((*T)->right) > 1) {if (target < (*T)->left->data)left_left(&*T);elseleft_right(&*T);}}else if (target > (*T)->data) {Del_node(&(*T)->right, target);if (get_height((*T)->right) - get_height((*T)->left) > 1) {if (target < (*T)->right->data)rigth_left(&*T);elseright_rigth(&*T);}}//此时(*T)就是要删除的节点//1.如果这个节点都有左右子树的话else if ((*T)->left && (*T)->right) {//找到右子树最左边的节点,也就是比这个要删除节点大一位的节点Node* min = (*T)->right;while (min->left)min = min->left;(*T)->data = min->data;Del_node(&(*T)->right, min->data);}//2.如果这个节点有一个左右子树或者没有子树的情况else {Node* dnode = (*T);(*T) = (*T)->left ? (*T)->left : (*T)->right;//把这个节点进行替换掉free(dnode);//释放空间,删除这个节点}//高度重新处理if((*T))(*T)->heigh=get_height((*T)->left)>get_height((*T)->right)? get_height((*T)->left)+1: get_height((*T)->right)+1;
}
4.平衡二叉树相关操作
4.1查找数据
查找数据然后返回这个节点,我们直接通过二分查找就行了,代码如下:
//查找数据节点
Node* Search_node(Node *T,Datatype target) {if (!T) {return NULL;}if (target == T->data)return T;else if (target < T->data)Search_node(T->left, target);elseSearch_node(T->right, target);
}
4.2判断是否为平衡二叉树
根据平衡二叉树的特性,我们需要判断这个二叉树是否排序,是否满足左右子树高度差不大于1 ,这里就需要用到递归一层一层检索了,最后取和运算,代码如下:
//判断一个树是否为平衡二叉树
bool Judge(Node* T) {if (!T){printf("NULL\n");exit(0);}if(T->left->data>T->data||T->right->data<T->data)return false;if (abs(get_height(T->left) - get_height(T->right)) > 1)return false;elsereturn true;return Judge(T->left)&&Judge(T->right);
}
4.3中序遍历输出
//中序遍历输出
void In_travel(Node* T) {if (!T)return;In_travel(T->left);printf("%d ", T->data);In_travel(T->right);
}
4.4销毁平衡二叉树
销毁平衡二叉树就要把每一个节点的空间释放掉,那就直接从下往上去释放空间,代码如下:
//销毁
void Destroy(Node** T) {if (!*T)return;Destroy(&(*T)->left);Destroy(&(*T)->right);free(*T);
}
以上就是本期的全部内容了,我们下一期再见!
分享一张壁纸:
相关文章:

数据结构-----平衡二叉树
目录 前言 1.平衡二叉树 1.1概念与特点 1.2与二叉排序树比较 1.3判断平衡二叉树 2.平衡二叉树的构建 2.1平衡因子 BF 2.2 LL型失衡(右旋) 2.3 RR型失衡(左旋) 2.4 LR型失衡(先左旋再右旋) 2.5 RL…...

vue3 keepalive翻页保存页面状态
描述 实现页面 A-> B , B->A(A保存之前页面状态,不刷新页面) // router/index.tsimport { createRouter, createWebHistory } from vue-router import HomeView from ../views/HomeView.vueconst router createRouter({h…...

测试工程师思维学习
一、测试工程师应具备什么思维? 透过现象看本质,拒绝“一叶障目” 01、质疑和系统思维 02、创新思维 03、全局思维 04、风险驱动和组合思维 05、用户为中心和比较思维 06、BT思维和架构扩展性思维 二、测试工程师应避免的思维 01、同化现象 02、定位效…...

前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— Web APIs(六)
思维导图 一、正则表达式 1.1正则表达式介绍 1.2 语法 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewpor…...

云硬盘和物理硬盘的区别
服务器的硬盘是服务器用来存储数据,一般有云硬盘和物理硬盘两种。云硬盘是云计算平台的虚拟技术的存储服务,将数据存储于云端通过分布式存储架构的形式。物理硬盘是将数据存储在服务器或者是PC端上,存储空间比较大,读写速度也很快…...

数据分析--观察数据处理异常值
引包: import pandas as pd import numpy as np 读取文件: dfpd.read_csv(./HR.csv) 文件见绑定资源(来自kaggle的HR.csv) 处理过程: 一、从df中拿出处理对象 二、找出缺失值的位置并删除 s1_sdf[satisfactio…...

vue3+elementPlus el-input的type=“number“时去除右边的上下箭头
改成 代码如下 <script lang"ts" setup> import {ref} from vue const inputBtn ref() </script> <template><el-input type"number" v-model"inputBtn" style"width: 80px;" class"no_number">…...

华为云云耀云服务器L实例评测|Elasticsearch的可视化Kibana工具安装 IK分词器的安装和使用
前言 最近华为云云耀云服务器L实例上新,也搞了一台来玩,期间遇到各种问题,在解决问题的过程中学到不少和运维相关的知识。 本篇博客介绍Elasticsearch的可视化Kibana工具安装,以及IK分词器的安装和使用。 其他相关的Elasticsea…...

加密货币交易技巧——人和(一)
交易原则 本篇主要讲述加密货币交易人需要注意的几个原则。 1.不能贪心,具体表现在做好仓位管理。第一,不要重仓进去,一定要轻仓。第二,开仓就想好本次要赚多少钱,不要太贪,到了预期点就止盈。第三&am…...

数学建模:最优化问题及其求解概述
数学建模:最优化问题及其求解概述 最优化问题定义分类离散优化问题连续优化问题 求解 此博客围绕运筹学以及最优化理论的相关知识,通俗易懂地介绍了最优化问题的定义、分类以及求解算法。 最优化问题 定义 数学优化(Mathematical Optimiza…...

企业办理CS资质,怎么选择办理等级?
信息系统建设和服务能力等级证书(Information system construction and service—Capability assessment system,简称:CS),由中国电子信息行业联合会组织开展的第三方评估活动,是根据《信息系统建设和服务能…...

华为云云耀云服务器L实例评测|Huawei Cloud EulerOS 自动化环境部署
[toc] Huawei Cloud EulerOS 自动化环境部署 云耀云服务器L实例【Huawei Cloud EulerOS 2.0 64bit】 Python Git Google Chrome Chromedriver Selenium More… 1. Python 镜像创建后自带。 2.Git 拉取项目。 sudo yum install git3. Google Chrome 使用root权限或sudo权…...

从一张表格开始做挖机报价系统
一、前言 历时4个月的挖机销售报价系统进入收尾阶段,由我直接负责与业务方对接,这中间各种折腾真是一言难尽,项目开发过程中还要维护POS系统以及牛奶配送系统,本项目我们采用的是迭代开发,今天讲一下具体的开发过程以…...

Qt扫盲-QTreeView 理论总结
QTreeView 理论使用总结 一、概述二、快捷键绑定三、提高性能四、简单实例1. 设计与概念2. TreeItem类定义3. TreeItem类的实现4. TreeModel类定义5. TreeModel类实现6. 在模型中设置数据 一、概述 QTreeView实现了 model 中item的树形表示。这个类用于提供标准的层次列表&…...

BF算法详解(JAVA语言实现)
目录 BF算法的介绍 图解 JAVA语言实现 BF算法的时间复杂度 BF算法的介绍 BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继…...

零基础转行网络工程师,过来人给的一些建议
最近收到好多同学的一些提问,零基础没经验,能不能转行到网络工程师?薪资能有多少?发展前景怎么样? 应该有不少朋友都有这个疑问,那么,今天我尽量给大家做出一个详细的解答,希望能有…...

Vue中如何进行分布式搜索与全文搜索(如Elasticsearch)
在Vue中实现分布式搜索与全文搜索(使用Elasticsearch) 分布式搜索和全文搜索在现代应用程序中变得越来越重要,因为它们可以帮助用户快速查找和检索大量数据。Elasticsearch是一种强大的分布式搜索引擎,它可以用于实现高性能的全文…...

数据结构-图-最小生成树问题
最小生成树 并查集定义举例说明查找某个元素属于哪个集合代码实现路径压缩 Kruskal算法原理代码实现 Prim算法原理代码实现 并查集 定义 🚀在一些应用问题中,需要将n个不同的元素分成一些不相交的集合。开始时,每个元素自成一个单元素集合&…...

使用vite+npm封装组件库并发布到npm仓库
组件库背景:使用elementplusvue封装了一个通过表单组件。通过JSX对el-form下的el-input和el-button等表单进行统一封装,最后达到,通过数据即可一键生成页面表单的功能。 1.使用vite创建vue项目 npm create vitelatest elementplus-auto-form…...

85.最大矩形
单调栈,时间复杂度o(mn),空间复杂度o(mn) class Solution { public:int maximalRectangle(vector<vector<char>>& matrix) {int mmatrix.size();if(m0){return 0;}int nmatrix[0].size();//记录矩阵中每个元素左边连续1的数量vector<…...

Windows服务器 开机自启动服务
1、新建txt,并粘贴下面脚本 start cmd /k "cd /d D:\ahjd&&java -jar clips-admin.jar" start cmd /k "cd /d D:\ahjd\dist&&simple-http-server.exe -i -p 8000"说明,脚本格式为:start cmd /k “cd /d…...

《算法通关之路》chapter17一些通用解题模板
《算法通关之路》学习笔记,记录一下自己的刷题过程,详细的内容请大家购买作者的书籍查阅。 1 二分法 1.1 普通二分法 # 查找nums数组中元素值为target的下标。如果不存在,则返回-1def bs(nums: list[int], target: int) -> int :l, h …...

常用求解器安装
1 建模语言pyomo Pyomo是一个Python建模语言,用于数学优化建模。它可以与不同的求解器(如Gurobi,CPLEX,GLPK,SCIP等)集成使用,以求解各种数学优化问题。可以使用Pyomo建立数学优化模型…...

第三章:最新版零基础学习 PYTHON 教程(第一节 - Python 运算符)
在Python编程中,运算符一般用于对值和变量进行操作。这些是用于逻辑和算术运算的标准符号。在本文中,我们将研究不同类型的Python 运算符。 运算符:这些是特殊符号。例如- + 、 * 、 / 等。操作数:它是应用运算符的值。目录 Python 中的运算符类型 Python 中的算术运算符…...

细粒度特征提取和定位用于目标检测:PPCNN
1、简介 近年来,深度卷积神经网络在计算机视觉上取得了优异的性能。深度卷积神经网络以精确地分类目标信息而闻名,并采用了简单的卷积体系结构来降低图层的复杂性。基于深度卷积神经网络概念设计的VGG网络。VGGNet在对大规模图像进行分类方面取得了巨大…...

【STM32单片机】数学自动出题器设计
文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器,使用按键、IIC OLED模块等。 主要功能: 系统运行后,OLED液晶显示出题器开机界面,默认结果范围为100,可按…...

C语言之动态内存管理篇(1)
目录 为什么存在动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 今天收假了,抓紧时间写几篇博客。我又来赶进度了。今天我们来讲解动态内存管理。🆗🆗 为什么存在动态内存分配 假设我们去实现一个…...

React18入门(第二篇)——React18+Ts项目配置husky、eslint、pretttier、commitLint
前言 我的项目版本如下: React: V18.2.0Node.js: V16.14.0TypeScript:最新版工具: VsCode 本文将采用图文详解的方式,手把手带你快速完成在React项目中配置husky、prettier、commitLint,实现编码规范的统…...

【VINS】苹果手机采集单目相机+IMU数据离线运行VINS-Mono
0.准备工作 开个新坑,之前用Android手机做过离线采集数据的实验,这次用IPhone来测试! 1.虚拟机配置Mac OS 下载一个Mac OS 的ios镜像,打开虚拟机按照跟Ubuntu差不多的方式安装,但是发现没有Mac OS的入口。 因为VMwa…...

数据结构 2.1 单链表
1.单链表 线性表:1.有限的序列 2.序列中的每一个元素都有唯一的前驱和后继,除了开头和结尾的两个节点。 顺序表:分配一块连续的内存去存放这些元素,eg、数组 链表:内存是不连续的,元素会各自被分配一块内…...