【C++】AVL树(高度平衡二叉树)

AVL树

      • 概念
      • AVL树节点定义
      • AVL树节点插入
        • AVL树四种旋转情况
          • 左单旋
          • 右单旋
          • 先左单旋再右单旋
          • 先右单旋后左单旋
      • 元素的插入及控制平衡
      • 判断最后节点是否平衡

概念

二叉搜索树虽然可以缩短查找的效率,但如果数据有序或者接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。
。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。

AVL树的特点:
它的左右子树都是AVL树
左右子树高度之差(简称平衡因子)的绝对值不超过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
{AVLTreeNode<K, V>* _left;// 该节点的左孩子AVLTreeNode<K, V>* _right;// 该节点的右孩子AVLTreeNode<K, V>* _parent;// 该节点的父节点pair<K, V> _kv;// 该节点的平衡因子int _bf;AVLTreeNode(const pair<K,V>& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_bf(0){}
};

AVL树节点插入

AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。那么
AVL树的插入过程可以分为两步:
1. 按照二叉搜索树的方式插入新节点
2. 调整节点的平衡因子

在这里插入图片描述

更新平衡因子的规则:
1、新增在右,parent->bf++; 新增在左,parent->bf–:
2、更新后,parent->bf == 1 r -1,说明parent插入前的平衡因子是0,说明左右子树高度相等,插入后有一边高,parent高度变了,需要继续往上更新
3、更新后,parent->bf == 0,说明parent插入前的平衡因子是1 r -1,说明左右子树一边高-边低,插入后两边一样高,插入填上了矮了那边,parent所在子树高度不变,不需要继续往上更新
4更新后,parent->bf == 2 r -2,说明parent插入前的平衡因子是1 or -1,已经平衡临界值,插入变成2 or -2,打破平衡,parent所在子树需要旋转处理。
5更新后,parent->bf > 2 r< -2的值,不可能,如果存在,则说明插入前就不是AVL树,需要去检查之前操作的问题.

AVL树四种旋转情况

左单旋

在这里插入图片描述

	void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL){subRL->_parent = parent;}Node* ppNode = parent->_parent;subR->_left = parent;parent->_parent = subR;//1.parent是整棵树的根//2.parent是子树的根if (parent == _root){_root = subR;subR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}subR->_bf = parent->_bf = 0;}
右单旋

在这里插入图片描述

	//右单旋void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR){subLR->_parent = parent;}Node* ppNode = parent->_parent;subL->_right = parent;parent->_parent = subL;if (ppNode == nullptr){_root = subL;subL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}parent->_bf = subL->_bf = 0;}
先左单旋再右单旋

在这里插入图片描述

void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);//旋转完后的根节点subLR->_bf = 0;if (bf == 1){subL->_bf = -1;}else if (bf == -1){parent->_bf = 0;subL->_bf = 1;}else if (bf == 0){parent->_bf = 0;subL->_bf = 0;}else{assert(false);}}
先右单旋后左单旋

在这里插入图片描述

	//右左双旋void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){subR->_bf = 1;parent->_bf = 0;}else if (bf == 0){subR->_bf = 0;parent->_bf = 0;}else{assert(false);}}

元素的插入及控制平衡

typedef AVLTreeNode<K, V> Node;bool Insert(const pair<K, V>& kv){//如果当前树为空直接设置节点if (_root == NULL){_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;//控制平衡//1.更新平衡因子while (parent){if (parent->_right == cur){parent->_bf++;}else{parent->_bf--;}if (parent->_bf == 0){break;}else if (abs(parent->_bf) == 1){	//如果为1整体向上移动再次调增平衡parent = parent->_parent;cur = cur->_parent;}else if (abs(parent->_bf) == 2){//说明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){RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}else{//预防调整出错情况assert(false);}break;}else{//预防调整出错情况assert(false);}}return true;}

判断最后节点是否平衡

	//判断是否平衡
bool _IsBanlance(Node* root){if (root == NULL){return true;}int leftH = _Height(root->_left);int rightH = _Height(root->_right);if (rightH - leftH != root->_bf){cout << root->_kv.first << "节点平衡因子异常" << endl;return false;}return abs(leftH - rightH) < 2&& _IsBanlance(root->_left)&& _IsBanlance(root->_right);}//计算它的最大高度int _Height(Node* root){if (root == nullptr){return 0;}int leftH = _Height(root->_left);int rightH = _Height(root->_right);return max(leftH, rightH) + 1;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/84764.html

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

相关文章

kali开启SSH服务(简单无比)

我会一直陪着你 1.切换到管理员用户&#xff1a;2.启动SSH服务3.要在Kali Linux上启用SSH服务并修改配置文件&#xff0c;你可以按照以下步骤进行操作&#xff1a;4.查看SSH服务状态是否正常运行&#xff0c;命令为&#xff1a;注意&#xff1a;配置文件有些地方不同&#xff0…

IDC发布《亚太决策支持型分析数据平台评估》报告,亚马逊云科技位列“领导者”类别

日前&#xff0c;领先的IT市场研究和咨询公司IDC发布《2023年亚太地区&#xff08;不含日本&#xff09;决策支持型分析数据平台供应商评估》1报告&#xff0c;亚马逊云科技位列“领导者”类别。IDC认为&#xff0c;亚马逊云科技在解决方案的协同性、敏捷性、完整性、及时性、经…

css之文字连续光影特效、动画、scss

文章目录 效果图htmlscsscss 效果图 html <div><span>C</span><span>O</span><span>L</span><span>O</span><span>R</span><span>F</span><span>U</span><span>L</span&…

使用 wxPython 和 pymupdf进行 PDF 加密

PDF 文件是一种常见的文档格式&#xff0c;但有时候我们希望对敏感信息进行保护&#xff0c;以防止未经授权的访问。在本文中&#xff0c;我们将使用 Python 和 wxPython 库创建一个简单的图形用户界面&#xff08;GUI&#xff09;应用程序&#xff0c;用于对 PDF 文件进行加密…

(vue)el-table 怎么把表格列中相同的数据 合并为一行

(vue)el-table 怎么把表格列中相同的数据 合并为一行 效果&#xff1a; 文档解释&#xff1a; 写法&#xff1a; <el-table:data"tableData"size"mini"class"table-class"borderstyle"width:100%"max-height"760":span-…

Stable Diffusion 系列教程 | 打破模型壁垒

目录 1.模型基本分类 1.1 CheckPoint 大模型/底模型/主模型 1.2 VAE美化模型/变分自编码器 1.3 HyperNetwork 超网络 1.4 embeddings&#xff08;/Textual Inversion&#xff09; 嵌入式向量 1.5 loRa 低秩适应模型 2. 下载途径和渠道 2.1 C站 2.1.1 如何筛选到自己需…

Anolis 8.6 下 Redis 7.2.0 集群搭建和配置

Redis 7.2.0 搭建和集群配置 一.Redis 下载与单机部署1.Redis 下载2.虚拟机配置3.Redis 单机源码安装和测试4.Java 单机连接测试1.Pom 依赖2.配置文件3.启动类4.配置类5.单元测试6.测试结果 二.Redis 集群部署1.主从1.从节点配置2.Java 测试 2.哨兵1.哨兵节点配置2.复制一个哨兵…

【python】Leetcode(primer-dict-list)

文章目录 260. 只出现一次的数字 III&#xff08;字典 / 位运算&#xff09;136. 只出现一次的数字&#xff08;字典&#xff09;137. 只出现一次的数字 II&#xff08;字典&#xff09;169. 求众数&#xff08;字典&#xff09;229. 求众数 II&#xff08;字典&#xff09;200…

字符串经典问题

1. 验证回文串 验证回文串 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&#xff0c;如果它是 回文串 &#xff0c;返回 t…

2023年7月天猫糕点市场数据分析(天猫数据怎么看)

烘焙食品行业是近几年食品领域比较火热的赛道之一&#xff0c;随着居民饮食结构的变化&#xff0c;人均消费水平的上升&#xff0c;蛋糕、面包等烘焙糕点越发成为消费者饮食的重要组成部分。同时&#xff0c;在烘焙糕点市场中&#xff0c;老品牌不断推新迭变&#xff0c;新品牌…

芯科科技推出专为Amazon Sidewalk优化的全新片上系统和开发工具,加速Sidewalk网络采用

芯科科技为Sidewalk开发提供专家级支持 中国&#xff0c;北京 - 2023年8月22日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#xff1a;SLAB&#xff09;今日在其一年一度的第四…

大数据Flink(六十八):SQL Table 的基本概念及常用 API

文章目录 SQL & Table 的基本概念及常用 API 一、​​​​​​​一个 Table API\SQL任务的代码结构