AVL Tree (1) - Definition, find and Rotation
1. 定义
- (15-1) [AVL tree]:
- 一棵空二叉树是 AVL tree;
- 若 T 是一棵非空二叉树, 则 T 满足以下两个条件时, T 是一棵 AVL tree:
- T_LeftSubtree 和 T_RightSubtree 是 AVL tree.
- \(| h_{Left} - h_{Right}| \leq 1\).
- [AVL search tree]: AVL tree + binary search tree.
- AVL tree 的高度 \(h=O(\log{n})\)
- [balance foctor] 平衡因子可能取值为
-1,0,1;
对于 nodex, \(bf(x)\) 定义为: \(h_{x\_LeftSubtree} - h_{x\_RightSubtree}\).
AVL Tree 的宗旨在于使 BST 保持平衡, 进而避免 BST 过度倾斜 (极端情况下 BST 有可能成为链表) .
2. btNode 和 AVLTree 的定义
<utility> 头文件提供了 std::pair 的定义, 便于使用融合 key 类型和 value 类型的复合类型.
<iostream> 头文件提供的输出方法由 private method preOrder 使用, 以测试代码正确性.
Click to show the codes
// AVL Tree
#include <utility>
#include <iostream>
/**
* @brief Binary tree node.
* @tparam T Should be std::pair<Key_Type, Element_Type> in binary search tree.
*/
template<class T>
struct btNode
{
T data;
btNode<T>* left, * right;
// Constructor for btNode.
btNode(T d = {}, btNode<T>* l = nullptr, btNode<T>* r = nullptr) :
data(d), left(l), right(r) {}
};
template<class K, class E>
class AVLTree
{
public:
// Constructor for AVLTree.
AVLTree() :root(nullptr) {}
// @brief PreOrder ouput.
void preOrder() { preOrder(this->root); }
public:
// @brief Find the node with key {tKey} and return its address.
btNode<std::pair<K, E>>* find(const K& theKey) const;
// @brief [Iteration] Create a node with {tPair} and insert it to the tree.
void insert_I(const std::pair<K, E>& tPair);
// @brief [Recursion] Create a node with {tPair} and invoke method {m_insert_R}.
void insert_R(const std::pair<K, E>& tPair);
// @brief [Iteration] Erase the node with key {tKey}.
void erase_I(const K& tKey);
// @brief [Recursion] Erase the node with key {tKey}.
void erase_R(const K& tKey);
private: // Rotate methods.
// @brief Right rotate subtree whose root is {tRoot}, return {tRoot->left} as new root.
// e.g. To rotate {parentTarget->left} : parentTarget->left = rightRotate(parentTarget->left)
inline btNode<std::pair<K, E>>* rightRotate(btNode<std::pair<K, E>>* tRoot);
// @brief Left rotate subtree whose root is {tRoot}, return {tRoot->right} as new root.
// e.g. To rotate {parentTarget->left} : parentTarget->left = leftRotate(parentTarget->left);
inline btNode<std::pair<K, E>>* leftRotate(btNode<std::pair<K, E>>* tRoot);
// @brief For LL case, right rotate subtree {tRoot}, return {tRoot->left} as new root.
// e.g. To rotate {parentTarget->left} : parentTarget->left = llRotation(parentTarget->left);
inline btNode<std::pair<K, E>>* llRotation(btNode<std::pair<K, E>>* tRoot);
// @brief For RR case, left rotate subtree {tRoot}, return {tRoot->left} as new root.
// e.g. To rotate {parentTarget->left} : parentTarget->left = rrRotation(parentTarget->left);
inline btNode<std::pair<K, E>>* rrRotation(btNode<std::pair<K, E>>* tRoot);
// @brief For LR case, left rotate {tRoot->left}, right rotate {tRoot}, return {tRoot->left->right}.
// e.g. To rotate {parentTarget->left} : parentTarget->left = lrRotation(parentTarget->left);
inline btNode<std::pair<K, E>>* lrRotation(btNode<std::pair<K, E>>* tRoot);
// @brief For RL case, right rotate {tRoot->right}, left rotate {tRoot}, return {tRoot->right->left}.
// e.g. To rotate {parentTarget->left} : parentTarget->left = rlRotation(parentTarget->left);
inline btNode<std::pair<K, E>>* rlRoattion(btNode<std::pair<K, E>>* tRoot);
private:
// @brief Private recurse method to insert.
btNode<std::pair<K, E>>* m_insert_R(btNode<std::pair<K, E>>* tRoot, btNode<std::pair<K, E>>* tNode);
// @brief Private recurse method to erase.
btNode<std::pair<K, E>>* m_erase_R(btNode<std::pair<K, E>>* tRoot, const K& tKey);
// @brief Private recurse method for preorder output.
void preOrder(btNode<std::pair<K, E>>* tRoot);
private:
btNode<std::pair<K, E>>* root;
};
template<class K, class E>
void AVLTree<K, E>::preOrder(btNode<std::pair<K, E>>* tRoot)
{
if (!tRoot) return;
std::cout << tRoot->data.second;
preOrder(tRoot->left);
preOrder(tRoot->right);
}
3. Find
解释可以参照 BST 的 find 方法.
Click to show the codes
// @brief Find the node with key {tKey} and return its address.
template<class K, class E>
btNode<std::pair<K, E>>* AVLTree<K, E>::find(const K& theKey) const
{
// {keyNode} traverse the tree, searching for matched node.
btNode<std::pair<K, E>>* keyNode = root;
// Iteration ends if {keyNode} is nullptr.
while (keyNode) {
if (theKey < keyNode->data.first) {
keyNode = keyNode->left;
} else if (theKey > keyNode->element.first) {
keyNode = keyNode->right;
}
// ELSE: {keyNode->data.first} equals {tKey}.
else {
return keyNode;
}
}
// No matching pair.
return nullptr;
}
4. Left Rotate & Right Rotate
在探讨何时要旋转以及如何旋转之前, 我们不妨先实现两个单纯的左右旋转方法.

上图中左边是向右旋转 rightRotate , 右边是向左旋转 leftRotate .
很直观, 也没什么好多说的, 上代码.
Click to show the codes
// @brief Right rotate subtree whose root is {tRoot}, return {tRoot->left} as new root.
// e.g. To rotate {parentTarget->left} : parentTarget->left = rightRotate(parentTarget->left)
template<class K, class E>
inline btNode<std::pair<K, E>>* AVLTree<K, E>::rightRotate(btNode<std::pair<K, E>>* tRoot)
{
btNode<std::pair<K, E>>* new_tRoot = tRoot->left;
tRoot->left = new_tRoot->right;
new_tRoot->right = tRoot;
return new_tRoot;
}
// @brief Left rotate subtree whose root is {tRoot}, return {tRoot->right} as new root.
// e.g. To rotate {parentTarget->left} : parentTarget->left = leftRotate(parentTarget->left)
template<class K, class E>
inline btNode<std::pair<K, E>>* AVLTree<K, E>::leftRotate(btNode<std::pair<K, E>>* tRoot)
{
btNode<std::pair<K, E>>* new_tRoot = tRoot->right;
tRoot->right = new_tRoot->left;
new_tRoot->left = tRoot;
return new_tRoot;
}
5. 4 Cases for Rotation
AVL Tree 保持平衡的方法是计算 balance factor 后进行旋转.
下面四张图展示了需要旋转的 4 种情况以及旋转的方式.




实现四种情况的旋转的代码:
Click to show the codes
// @brief For LL case, right rotate subtree {tRoot}, return {tRoot->left} as new root.
// e.g. To rotate {parentTarget->left} : parentTarget->left = llRotation(parentTarget->left);
template<class K, class E>
inline btNode<std::pair<K, E>>* AVLTree<K, E>::llRotation(btNode<std::pair<K, E>>* tRoot)
{
return rightRotate(tRoot);
}
// @brief For LL case, left rotate subtree {tRoot}, return {tRoot->left} as new root.
// e.g. To rotate {parentTarget->left} : parentTarget->left = rrRotation(parentTarget->left);
template<class K, class E>
inline btNode<std::pair<K, E>>* AVLTree<K, E>::rrRotation(btNode<std::pair<K, E>>* tRoot)
{
return leftRotate(tRoot);
}
// @brief For LR case, left rotate {tRoot->left}, right rotate {tRoot}, return {tRoot->left->right}.
// e.g. To rotate {parentTarget->left} : parentTarget->left = lrRotation(parentTarget->left);
template<class K, class E>
inline btNode<std::pair<K, E>>* AVLTree<K, E>::lrRotation(btNode<std::pair<K, E>>* tRoot)
{
tRoot->left = leftRotate(tRoot->left);
return rightRotate(tRoot);
}
// @brief For RL case, right rotate {tRoot->right}, left rotate {tRoot}, return {tRoot->right->left}.
// e.g. To rotate {parentTarget->left} : parentTarget->left = rlRotation(parentTarget->left);
template<class K,class E>
inline btNode<std::pair<K, E>>* AVLTree<K, E>::rlRoattion(btNode<std::pair<K, E>>* tRoot)
{
tRoot->right = rightRotate(tRoot->right);
return leftRotate(tRoot);
}
Reference |
(1) Data Structures, Algoritms, and Applications in C++, Sartaj Sahni
(2) AVL Tree | Set 1 (Insertion), princiraj1992, rathbhupendra, Akanksha_Rai, sohamshinde04, nocturnalstoryteller, rdtank, kaiwenzheng644, hardikkoriintern
AVL Tree (1) - Definition, find and Rotation的更多相关文章
- AVL Tree Insertion
Overview AVL tree is a special binary search tree, by definition, any node, its left tree height and ...
- 04-树5 Root of AVL Tree
平衡二叉树 LL RR LR RL 注意画图理解法 An AVL tree is a self-balancing binary search tree. In an AVL tree, the he ...
- 1066. Root of AVL Tree (25)
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...
- 1066. Root of AVL Tree
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child su ...
- 树的平衡 AVL Tree
本篇随笔主要从以下三个方面介绍树的平衡: 1):BST不平衡问题 2):BST 旋转 3):AVL Tree 一:BST不平衡问题的解析 之前有提过普通BST的一些一些缺点,例如BST的高度是介于lg ...
- 1123. Is It a Complete AVL Tree (30)
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...
- A1123. Is It a Complete AVL Tree
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...
- A1066. Root of AVL Tree
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...
- PAT A1123 Is It a Complete AVL Tree (30 分)——AVL平衡二叉树,完全二叉树
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child sub ...
随机推荐
- 从20s优化到500ms,我用了这三招
前言 接口性能问题,对于从事后端开发的同学来说,是一个绕不开的话题.想要优化一个接口的性能,需要从多个方面着手. 其实,我之前也写过一篇接口性能优化相关的文章<聊聊接口性能优化的11个小技巧&g ...
- vue2.0 双向绑定原理分析及简单实现
Vue用了有一段时间了,每当有人问到Vue双向绑定是怎么回事的时候,总是不能给大家解释的很清楚,正好最近有时间把它梳理一下,让自己理解的更清楚,下次有人问我的时候,可以侃侃而谈. 一.首先介绍Obje ...
- 【转载】vscode配置C/C++环境
VScode中配置 C/C++ 环境 Tip:请在电脑端查看 @零流@火星动力猿 2022.4.12 1. 下载编辑器VScode 官网:https://code.visualstudio.com/( ...
- IO流原理及流的分类
IO原理 I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于 处理设备之间的数据传输.如读/写文件,网络通讯等. Java程序中,对于数据的输入/输出操作以"流(st ...
- 5-20 Web服务器和Nginx
什么是Web服务器 简单来说 Web服务器就是一个能够接收http请求并作出响应的java程序 我们再二阶段编写的webServer项目其实就是我们手写的Web服务器 我们现在开发的标准SpringB ...
- day01 File类_Lambda
File类 File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径) 使用File可以做到: 1:访问其表示的文件或目录的属性信息,例如:名字,大小,修改时间等等 ...
- python中的标识符和保留字
保留字,有一些单词被赋予了特定的意义,这些单词不能作为对象的名字 想要快速获取python中的关键字可以通过以下的程 序来快速实现 import keyword print(keyword.kwlis ...
- Odoo14 自定义widget小部件
不多说先上源码. 1 odoo.define('my_company_users_widget', function (require) { 2 "use strict"; 3 4 ...
- Odoo14 给模块/应用加小图标
# apps中的图标是固定路劲: static/description/icon.png # 主页图标是通过你的主menuitem的web_icon来设置的: <menuitem id=&quo ...
- GreatSQL特性介绍及未来展望--叶金荣|万里数据库
「3306π」是由业内知名MySQL专家叶金荣.吴炳锡首发倡议成立,围绕MySQL及云数据库.大数据等周边相关技术的技术爱好者的社区.致力于把互联网技术带到传统行业里,推动开源技术在传统行业中应用.本 ...