平衡二叉树平衡因子怎么计算_平衡二叉树(AVL Tree)旋转机制分析
平衡二叉树(AVL Tree)
概述
AVL树是以二分搜索树(BST)为底层数据结构而实现的,其特性是需要维护AVL的|平衡因子| <= 1
平衡因子
对于一个父节点的左右子树高度差的绝对值需要 <= 1
AVL最复杂的操作在于add()
和remove()
两个方法需要维护AVL的平衡二叉树特性,细节在下面展开
节点类
由于需要知道AVL一个节点的高度,因此需要在BST的内部类Node
中新维护一个成员变量height
public class Node<K, V> {K key;V value;int height;Node<K, V> left, right;public Node(K key, V value) {this.key = key;this.value = value;this.left = null;this.right = null;this.height = 1;}
}
IMap接口
该接口定义了BST的方法
public interface IMap<K, V> {void add(K key, V value);V remove(K key);boolean contains(K key);V get(K key);void set(K key, V value);int getSize();boolean isEmpty();
}
AVLTree类
成员变量以及构造方法
private int size;
private Node<K, V> root;public AVLTree() {root = null;size = 0;
}
基本的方法
下面的方法均是为了实现add()
和remove()
方法时,可能造成AVL的平衡性被打破而封装的辅助方法
- getHeight()
private int getHeight(Node<K, V> node) {if (node == null) {return 0;}return node.height;
}
该方法用于获取某节点的高度,且维护node
为null
时可能抛出的异常
- getNode(Node node, K key)
private Node<K, V> getNode(Node<K, V> node, K key) {if (root == null) {return null;}if (key.compareTo(node.key) == 0) {return node;} else if (key.compareTo(node.key) < 0) {return getNode(node.left, key);} else {return getNode(node.right, key);}
}
根据key获取节点
- getBalanceFactor(Node node)
// 获取平衡因子
private int getBalanceFactor(Node<K, V> node) {if (node == null) {return 0;}return getHeight(node.left) - getHeight(node.right);
}
获取平衡因子,并且维护了node
可能为null
而抛出异常的情况
核心方法
- add(Node node)
@Override
public void add(K key, V value) {root = add(root, key, value);
}private Node<K, V> add(Node<K, V> node, K key, V value) {if (node == null) {size++;return new Node<>(key, value);}if (key.compareTo(node.key) < 0) {node.left = add(node.left, key, value);} else if (key.compareTo(node.key) > 0) {node.right = add(node.right, key, value);} else {// 如果插入节点存在,此处定义为改变 Value 的值(也可以根据情况不做改变)node.value = value;}node.height = Math.max(getHeight(node.left), getHeight(node.right) + 1);int balanceFactor = getBalanceFactor(node);// 平衡维护// LLif (balanceFactor > 1 && getBalanceFactor(node.left) >= 0) {return rightRotate(node);}// RRif (balanceFactor < -1 && getBalanceFactor(node.right) <= 0) {return leftRotate(node);}// LRif (balanceFactor > 1 && getBalanceFactor(node.right) < 0) {node.left = leftRotate(node.left);return rightRotate(node);}// RLif (balanceFactor < -1 && getBalanceFactor(node.right) > 0) {node.right = leftRotate(node);return rightRotate(node.right);}return node;
}
- remove(K key)
@Override
public V remove(K key) {Node<K, V> node = getNode(root, key);if (node != null) {root = remove(root, key);return node.value;}return null;
}private Node<K, V> remove(Node<K, V> node, K key) {if (node == null) {return null;}Node<K, V> retNode;if (key.compareTo(node.key) < 0) {node.left = remove(node.left, key);retNode = node;} else if (key.compareTo(node.key) > 0) {node.right = remove(node.right, key);retNode = node;} else {if (node.left == null) {Node<K, V> rightNode = node.right;node.right = null;size--;retNode = node;}if (node.right == null) {Node<K, V> leftNode = node.left;node.left = null;size--;retNode = node;}// 左右子树均不为空的情况Node<K, V> minimum = minimum(node.right);minimum.right = removeMin(node.right);minimum.left = node.left;node.left = node.right = null;retNode = minimum;}retNode.height = 1 + Math.max(getHeight(retNode.left), getHeight(retNode.right));int balanceFactor = getBalanceFactor(retNode);// 平衡维护// LLif (balanceFactor > 1 && getBalanceFactor(retNode.left) >= 0) {return rightRotate(retNode);}// RRif (balanceFactor < -1 && getBalanceFactor(retNode.right) <= 0) {return leftRotate(retNode);}// LRif (balanceFactor > 1 && getBalanceFactor(retNode.right) < 0) {retNode.left = leftRotate(retNode.left);return rightRotate(retNode);}// RLif (balanceFactor < -1 && getBalanceFactor(retNode.right) > 0) {retNode.right = leftRotate(retNode);return rightRotate(retNode.right);}return retNode;
}
维护AVL的平衡性质——旋转
这里是文章的核心内容,即如何保证AVL的平衡性质,这里开始详细描述维护AVL特性的机制——旋转
旋转分为四种形式,分别为:
- LL旋转
- RR旋转
- LR旋转
- RL旋转
只需要理解一种旋转机制,就可以理解其它的旋转机制
这里以LL和LR旋转为例
LL旋转
- 如图所示,根节点的
平衡因子
为2,而破坏该AVL的节点在根节点的左子树的左节点,因此需要LL旋转来维护其平衡
- 接下来根据实际代码进一步理解这个机制
- 为了结合代码,现在虚拟出三个节点(或子树),它们可以是
null
,也可以实际存在
- 目前由于是LL旋转,那么提供一个private方法用于维护平衡,下面给出方法详细代码,代码后有每一个表达式的详细解释
// 右旋转
private Node<K, V> rightRotate(Node<K, V> y) {Node<K, V> x = y.left;Node<K, V> t3 = x.right;x.right = y;y.left = t3;// 更新heighty.height = Math.max(getHeight(y.left), getHeight(y.right)) + 1;x.height = Math.max(getHeight(x.left), getHeight(x.right)) + 1;return x;
}
- 第一行表达式
Node<K, V> x = y.left
,将发现节点y
的左子树暂存
- 第二行表达式
Node<K, V> t3 = x.right
,将单独拿出的节点的右子树t3
暂存
- 第三行表达式
x.right = y
,将发现节点y
接入x
的右子树
- 第四行表达式
y.left = t3
,将暂存节点t3
插入发现节点y
的左节点
- 注意:以上的每个操作都是满足了二分搜索树(BST)的特性,这点对于理解旋转机制很重要
- 由于最终平衡后的AVL高度发生了改变,因此需要对更新后的AVL高度进行维护
// 更新height
y.height = Math.max(getHeight(y.left), getHeight(y.right)) + 1;
x.height = Math.max(getHeight(x.left), getHeight(x.right)) + 1;
LR旋转
LR旋转和LL旋转的差别在于LR旋转需要进行两次旋转操作,具体步骤如下:
- 首先对于上面的AVL进行一次
左旋转
,然后就会暂时将其转变为LL旋转的状态
- 然后再进行一次
右旋转
,即可恢复到AVL的状态
易错点分析
AVL有一个非常容易误解的地方,如图
实际上旋转的命名(LL、RR、LR、RL)也都是根据破坏节点t1(t2)
与发现节点y
的相对位置命名
也就是说无论是:
还是:
旋转方式是相同的,均为LL旋转,结果如图:
平衡二叉树平衡因子怎么计算_平衡二叉树(AVL Tree)旋转机制分析相关推荐
- 平衡二叉树平衡因子怎么计算_数据结构PHP 平衡二叉树(AVL)的平衡原理
这篇文章主要介绍一下 平衡二叉树(AVL),对于 二分搜索树 来说,如果树上的 元素 是顺序 添加的,会导致数据退化成一个 链表,这样就会造成很严重的性能问题,此时就需要在 二分搜索树 的基础上,保证 ...
- 平衡二叉树平衡因子_数据结构:平衡二叉树
1.基本概念 平衡二叉树(AVL树),或为空树,或为如下性质的二叉排序树:左右子树深度之差的绝对值不超过1;左右子树仍然为平衡二叉树. 平衡因子BF=左子树深度-右子树深度. 平衡二叉树每个结点 ...
- 板式橡胶支座弹性模量怎样计算_板式橡胶支座抗压弹性模量试验分析(详细)
板式橡胶支座抗压弹性模量试验分析 1. 概述近年来我国交通事业发展迅速 , 桥梁作为我国重要社会基础设施的 地位愈显突出 , 在国民经济和居民日常生活中发挥着重要作用 . 桥梁支座 是桥粱结构的 重要 ...
- 流式凋亡率计算_流式细胞仪检测细胞凋亡率案例分析报告
一.实验材料 NCI-H1299,购自上海晶莱生物技术有限公司. 表 2.1.1 主要试剂试剂与耗材厂家(货号) 细胞培养瓶FALCON 中国(353014) Penicillin/streptomy ...
- c语言求平衡因子,平衡二叉树(AVL树)的基本操作
0x00.平衡二叉树的定义 平衡二叉树(AVL树)是一种特殊的二叉搜索树,只是在二叉搜索树上增加了对"平衡"的需求. 假如一棵二叉搜索树,按照"1,2,3,4,5&quo ...
- 高度平衡二叉树的构建_平衡二叉树(AVL)树
1.平衡二叉树定义 是一种二叉排序树(二叉查找树.二叉搜索树),其中每个节点的左子树和右子树的高度差不大于1.(左右子树也是平衡二叉树) 平衡因子BF = 二叉树节点的左子树深度减去右子树深度 = 节 ...
- [转]C#与数据结构--树论--平衡二叉树(AVL Tree)
C#与数据结构--树论--平衡二叉树(AVL Tree) http://www.cnblogs.com/abatei/archive/2008/11/17/1335031.html 介绍 我们知道在二 ...
- ds查找—二叉树平衡因子_面试官让我手写一个平衡二叉树,我当时就笑了
平衡二叉树对于初学者一直是一个比较复杂的知识点,因为其里面涉及到了大量的旋转操作.把大量的同学都给转晕了.这篇文章最主要的特点就是通过动画的形式演示.确保大家都能看懂.最后是手写一个平衡二叉树. 一. ...
- 平衡二叉树及其操作实现_平衡二叉树(AVL树)及C语言实现
上一节介绍如何使用二叉排序树实现动态查找表,本节介绍另外一种实现方式--平衡二叉树.平衡二叉树,又称为 AVL 树.实际上就是遵循以下两个特点的二叉树: 每棵子树中的左子树和右子树的深度差不能超过 1 ...
最新文章
- 查询mysql上传大小限制_解决数据库phpmyadmin中上传最大限制:2,048 KB
- 简述python在量化金融中应用_Python金融与量化投资分析应用
- 同步、异步事件循环(宏任务、微任务「大厂真题解析」)
- SpringMCV整合配置文件
- zotero 相关文章链接 (侵权请联系,立即删除)
- Android - UI
- 用PS给证件照换底色
- SyntaxError: Non-UTF-8 code starting with ‘\xd5‘ in file
- 概要设计的过程和任务
- 515. 在每个树行中找最大值(中等 树 广度优先搜索 二叉树)
- 快速的在Adobe Illustrator中创建羊驼插图教程
- win10中conda activate激活环境出错的解决办法
- 熬夜肝了万字Android View 知识体系
- 简单快速清理 联想电脑 顽固可疑程序文件 comup.dll(风险名称: Adware/Hyideo )的方法 PS:该方法对于删除 .dll 文件均有效
- linux DNS jnl ixfr axfr 小解
- 【滤波】基于最近邻算法实现多目标航迹关联附matlab代码
- DirectX12(D3D12)基础教程(十七)——让小姐姐翩翩起舞(3D骨骼动画渲染【6】)
- aac是什么音频格式?aac转化为mp3方法
- 智慧养老解决方案探索养老行业新方向-新导智能
- 走x86路线的海光如今怎么样了?
热门文章
- Spring入门详细教程(四)
- linux文件权限_Linux的文件特殊权限
- cuda 安装_win10+VS 2017 安装 CUDA(Visual Studio Integration失败)
- Selenium之XPATH轴定位(第三篇)
- mysql 过程和函数 变量的值_MySQL数据库提升篇-----存储过程和函数
- php贺卡生成,用php与mysql的电子贺卡程序
- wxpython应用程序对象与顶级窗口_wxPython 基础 | 学步园
- android小程序源代码_我从 Android 转到微信小程序的思考
- spark sql 查看分区_Spark 3.0 中七个必须知道的 SQL 性能优化
- laravel 5.5 顶部带条件分页查询