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

【C++】AVL树的插入操作实现以及验证是否正确(带平衡因子)

文章目录

  • 前言
  • 一、AVL树结点的定义
  • 二、AVL树的插入(Insert)
    • 插入完整代码:
    • 1.左单旋(RotateL)
    • 2.右单旋(RotateR)
    • 3.先右单旋再左单旋(RotateRL)
      • 1.保存的bf为0
      • 2.保存的bf为1
      • 3.保存的bf为-1
    • 4.先左单旋再右单旋(RotateLR)
  • 三、AVL树的验证


前言

一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
1.它的左右子树都是AVL树
2.左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)

如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 O ( l o g 2 n ) O(log_2 n) O(log2n),搜索时间复杂度O( l o g 2 n log_2 n log2n)。

一、AVL树结点的定义

template<class K,class V>
//我们这里用键值的数据类型来举例
struct AVLTreeNode {pair<K, V> _kv;AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;//(父结点)int _bf;//(平衡因子大小)AVLTreeNode(const pair<K, V>& kv)//构造函数:_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0){}
};

二、AVL树的插入(Insert)

AVL树的插入过程可以分为两步:

  1. 按照二叉搜索树的方式插入新节点
  2. 调整节点的平衡因子

在这里插入图片描述

插入完整代码:

typedef AVLTreeNode<K, V> Node;
bool Insert(const pair<K, V>& kv) {if (_root == nullptr) {//若为空树就先建立结点_root = new Node(kv);return  true;}Node* cur = _root;Node* parent = nullptr;while (cur) {//寻找要插入结点的父亲的位置if (cur->_kv.first < kv.first) {parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first) {parent = cur;cur = cur->_left;}else {return false;}}cur = new Node(kv);//找到要插入结点父亲后,寻找插入其左边还是右边if (parent->_kv.first < kv.first) {parent->_right = cur;}else {parent->_left = cur;}cur->_parent = parent;while (parent) {//更新平衡因子if (parent->_left == cur) {parent->_bf--;}else {parent->_bf ++ ;}// 更新后检测双亲的平衡因子if (parent->_bf == 0) {break;}else if (parent->_bf == 1 || parent->_bf == -1) {// 插入前双亲的平衡因子是0,插入后双亲的平衡因为为1 或者 -1 ,说明以双亲//为根的二叉树的高度增加了一层,因此需要继续向上调整cur = parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2) {// 双亲的平衡因子为正负2,违反了AVL树的平衡性,需要对以parent// 为根的树进行旋转处理if (parent->_bf == 2 && cur->_bf == 1) {RotateL(parent);//左单旋}else if (parent->_bf == -2 && cur->_bf == -1) {RotateR(parent);//右单旋}else if (parent->_bf == 2 && cur->_bf == -1) {RotateRL(parent);//双旋}else if (parent->_bf == -2 && cur->_bf == 1) {RotateLR(parent);//双旋}break;}else {assert(false);}}return true;}

1.左单旋(RotateL)

在这里插入图片描述
在这里插入图片描述

 void RotateL(Node* parent) {Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;//  核心操作if (curleft) {//因为curleft可能为空curleft->_parent = parent;}Node* ppnode = parent->_parent;//提前记录下父结点的父亲cur->_left = parent;//     核心操作parent->_parent = cur;if (ppnode == nullptr) {//判断原先parent是否为根节点//因为根节点的父亲为空_root = cur;cur->_parent = nullptr;}else {//说明parent不为根节点//parent可能为ppnode的左或者右子树,改变ppnode的指向if (ppnode->_left == parent) {ppnode->_left = cur;}else {ppnode->_right = cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;// 根据调整后的结构更新部分节点的平衡因子} 

2.右单旋(RotateR)

在这里插入图片描述

 void RotateR(Node* parent) {Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if (curright) {//因为curleft可能为空curright->_parent = parent;}cur->_right = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if (ppnode == nullptr) {//判断原先parent是否为根节点//因为根节点的父亲为空_root = cur;cur->_parent = nullptr;}else {//说明parent不为根节点//parent可能为ppnode的左或者右子树,改变ppnode的指向if (ppnode->_left == parent) {ppnode->_left = cur;}else {ppnode->_right = cur;}cur->_parent = ppnode;}parent->_bf = cur->_bf = 0;// 根据调整后的结构更新部分节点的平衡因子} 

3.先右单旋再左单旋(RotateRL)

以cur为旋转点进行右旋,以parent为旋转点进行左旋,之后进行平衡因子的修改

 void RotateRL(Node* parent) {Node* cur = parent->_right;Node* curleft = cur->_left;int bf = curleft->_bf;// 旋转之前,保存curleft的平衡因子,旋转完成之后,需要根据该平衡因子来调整其他节//点的平衡因子RotateR(cur);RotateL(parent);if (bf == 0) {cur->_bf = 0;curleft->_bf = 0;parent->_bf = 0;}else if (bf == 1) {cur->_bf = 0;curleft->_bf = 0;parent->_bf = -1;}else if (bf == -1){cur->_bf = 1;curleft->_bf = 0;parent->_bf = 0;}else{assert(false);}} 

1.保存的bf为0

在这里插入图片描述

2.保存的bf为1

在这里插入图片描述

3.保存的bf为-1

在这里插入图片描述

4.先左单旋再右单旋(RotateLR)

以cur为旋转点进行左旋,以parent为旋转点进行右旋,之后进行平衡因子的修改

 void RotateLR(Node* parent) {Node* cur = parent->_left;Node* curright = cur->_right;int bf = curright->_bf;// 旋转之前,保存curright的平衡因子,旋转完成之后,需要根据该平衡因子来调整其他节//点的平衡因子RotateL(cur);RotateR(parent);if (bf == 0) {cur->_bf = 0;parent->_bf = 0;curright->_bf = 0;}else if (bf == -1){parent->_bf = 1;cur->_bf = 0;curright->_bf = 0;}else if (bf == 1){parent->_bf = 0;cur->_bf = -1;curright->_bf = 0;}else {assert(false);}} 

在这里插入图片描述

三、AVL树的验证

验证其为平衡树关键点:
1.每个节点子树高度差的绝对值不超过1(注意节点中如果没有平衡因子)
2.节点的平衡因子是否计算正确

int  Height(Node* root) {if (root == nullptr) {return 0;}int left =  Height(root->_left);int right =  Height(root->_right);return left > right ? left + 1 : right + 1;}bool IsBalance() {return IsBalance(_root);}bool IsBalance(Node* root) {if (root == nullptr) {return true;}int left = Height(root->_left);int right = Height(root->_right);if (right - left != root->_bf) {//节点的平衡因子是否计算正确cout << "平衡因子异常" << root->_kv.first << "=>" << root->_bf << endl;return false;}//每个节点子树高度差的绝对值不超过1//之后在验证左右子树return abs(right-left)<2&&IsBalance(root->_left) && IsBalance(root->_right);}

相关文章:

【C++】AVL树的插入操作实现以及验证是否正确(带平衡因子)

文章目录 前言一、AVL树结点的定义二、AVL树的插入&#xff08;Insert&#xff09;插入完整代码&#xff1a;1.左单旋&#xff08;RotateL&#xff09;2.右单旋&#xff08;RotateR&#xff09;3.先右单旋再左单旋&#xff08;RotateRL&#xff09;1.保存的bf为02.保存的bf为13…...

【Linux-Day10-信号量,共享内存,消息队列】

信号量 信号量描述 信号量是一个特殊的变量&#xff0c;一般取正数值。它的值代表允许访问的资源数目&#xff0c;获取资源 时&#xff0c;需要对信号量的值进行原子减一&#xff0c;该操作被称为 P 操作。 当信号量值为 0 时&#xff0c;代表没有资源可用&#xff0c;P 操作…...

使用IntelliJ IDEA本地启动调试Flink流计算工程的2个异常解决

记录&#xff1a;471 场景&#xff1a;使用IntelliJ IDEA本地启动调试Flink流计算时&#xff0c;报错一&#xff1a;加载DataStream报错java.lang.ClassNotFoundException。报错二&#xff1a;No ExecutorFactory found to execute the application。 版本&#xff1a;JDK 1.…...

对象及日期对象

对象 1.什么是对象 类是对象的抽象,对象是类的实例 程序算法数据结构 万物皆对象,对象是一个具体的事物,看到见摸得着,对象是一组无序相关属性和方法的集合(无序,所以对象没有length属性),所有事物都是对象,列如字符串,数值,数组,函数等. 属性:事物的特征,在对象中用属性表…...

鼠标滚轮编码器解析

文章目录 前言一、鼠标滚轮编码器逻辑&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 鼠标滚轮编码器为三脚接入&#xff0c;一个COM脚C&#xff08;一般是接地&#xff09;&#xff0c;两个脉冲波形输入脚A、B&#xff0c;转动滚轮编码器会在两个脉冲输入脚上产生脉冲…...

【PTA】攀拓(PAT)- 程序设计(甲级)2023年春季考试

个人学习记录&#xff0c;代码难免不尽人意。 今天又斥资买了今年春季的真题一试&#xff0c;呃&#xff0c;感觉尽力了&#xff0c;89分&#xff0c;在当年排名23&#xff0c;感觉还不错&#xff0c;没有出现读不懂的题目和没有思路的情况&#xff0c;扣的11分分别是第二题两个…...

Spring Cloud Gateway 实现原理

Spring Cloud Gateway是Spring Cloud生态系统中的一个组件&#xff0c;用于构建基于Spring Boot的微服务架构中的网关服务。它的主要目的是提供一种灵活的方式来路由、过滤和转换HTTP请求&#xff0c;从而允许您构建强大、高性能的微服务应用程序。 以下是Spring Cloud Gatewa…...

嘉泰实业:真实低门槛,安全有保障

在互联网金融大行其道的当下&#xff0c;无论用户是多么的青睐、喜爱这种便捷的理财方式&#xff0c;也一定得把资金安全放在心上。要投就投那些实力背景雄厚&#xff0c;诚信经营的平台&#xff0c;可以选择投资用户基数庞大的理财老品牌&#xff0c;也可以选择发展势头迅猛的…...

spring boot 2.7 -> 3.0升级指南

spring boot提供一个版本迁移指南 2.7 -> 3.0...

MQTT 连接优化指南

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…...

算法和数据结构学习中的一些小的工具函数

算法和数据结构学习中的一些小的工具函数 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;算法和数据结构学习中的一些小的工具函数 CSDN&#xff1a;算法和数据结构学习中的一些小的工具函数 提取一个数二进制最右侧的 1 比如二进制为&#xff1a;0100 0…...

解决2K/4K高分屏下Vmware等虚拟机下Kail Linux界面显示问题

问题现象 在我们日常使用VirtualBox、Vmware workstation、Hyper-V等虚拟机安装使用Kali系统&#xff0c;在2K/4K高分辨率电脑下Kali系统界面显示太小&#xff0c;包括各种软件及命令终端字体均无法很直观的看出&#xff0c;影响我们的正常测试及使用。 常规处理思路 很多人…...

【校招VIP】java语言考点之双亲委派模型

考点介绍&#xff1a; 双亲委派是校招面试中的高频考点之一。双亲委派机制定义: 当一个类加载器收到了类加载的请求的时候&#xff0c;他不会直接去加载指定的类&#xff0c;而是把这个请求委托给自己的父加载器去加载&#xff0c;只有父加载器无法加载这个类的时候&#xff0…...

2023年阿里云新用户云服务器价格表

阿里云&#xff0c;作为国内领先的云计算服务提供商&#xff0c;一直致力于为全球用户提供安全、稳定、高效的云计算服务。对于新用户来说&#xff0c;阿里云服务器是一个非常不错的选择。那么&#xff0c;阿里云新用户云服务器的价格是怎样的呢&#xff1f;本文将为大家详细介…...

信号相关名词概念汇总-采样周期、泄露、窗函数等

信号相关名词概念汇总-采样周期、泄露、窗函数等 以下为信号相关名词概念的汇总 1 名词解释 采样周期/间隔&#xff1a;采样频率的倒数&#xff0c;两次相邻采样之间的时间间隔采样时间&#xff1a;采样的总时长&#xff0c;即采样点数N和采样周期的乘积采样频率&#xff1a; …...

数字化新零售营销模式如何落地?数字化新零售营销功能推荐

​通过科技手段&#xff0c;针对对线下零售店面的客户进行消费行为、频次等的分析&#xff0c;并进一步整合线上线下资源&#xff0c;实现实体零售的效率充分化&#xff0c;便是目前很火的新零售营销模式&#xff0c;能够将实体门店与数字化技术进行有机结合&#xff0c;通过为…...

712. 两个字符串的最小ASCII删除和 -- 动规

712. 两个字符串的最小ASCII删除和 class MinimumDeleteSum:"""712. 两个字符串的最小ASCII删除和https://leetcode.cn/problems/minimum-ascii-delete-sum-for-two-strings/"""def solution(self, s1: str, s2: str) -> int:""&qu…...

python中的小tips

1、注释 1、注释快捷键&#xff1a; Ctrl/ 可以注释掉光标所在的这一行&#xff0c;或者是选中的区域。 对于注释掉的这一行或者这一区域&#xff0c;按下ctrl/则会去掉注释。 2、多行注释 在写多行注释时&#xff0c;英文状态下写三个"&#xff0c;会自动变成六个"&…...

高精度(加减乘除)

高精度算法出现的原因 当参与运算的数的范围大大的超出了标准数据类型&#xff0c;如int&#xff08;-2147483648 ~ 2147483647&#xff09;或者long long的范围&#xff0c;就需要使用高精度算法来进行数的运算。高精度运算的特点是代码长度比较长&#xff0c;本质是对数学运算…...

java企业数据管理系统

项目介绍 此项目为企业数据管理系统的后端部分&#xff0c;前端部分请参考vue-admin&#xff0c;项目实现了菜单管理、用户管理、角色管理和权限管理四个基础模块&#xff0c;前端菜单管理结合动态路由可自由添加菜单。结合Shiro权限管理实现了菜单和按钮的权限控制。 ❝ 前端…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...