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 ...
随机推荐
- js--js实现基础排序算法
前言 文本来总结常见的排序算法,通过 JvavScript 来实现 正文 1.冒泡排序 算法思想:比较相邻两个元素的大小,如果第一个比第二个大,就交换它们.从头遍历到尾部,当一轮遍历完后,数组最后一 ...
- 一文聊透 Netty 核心引擎 Reactor 的运转架构
本系列Netty源码解析文章基于 4.1.56.Final版本 本文笔者来为大家介绍下Netty的核心引擎Reactor的运转架构,希望通过本文的介绍能够让大家对Reactor是如何驱动着整个Nett ...
- Pytorch从0开始实现YOLO V3指南 part4——置信度阈值和非极大值抑制
本节翻译自:https://blog.paperspace.com/how-to-implement-a-yolo-v3-object-detector-from-scratch-in-pytorch ...
- Collection集合和Collection集合常用功能
Collection集合常用功能 方法: boolean add(E e); 向集合中添加元素 boolean remove(E e); 删除集合中的某个元素 void clear(); 清空集合所有 ...
- 使用docker buildx打包发布多平台镜像
2022-07-07 个人比较喜欢影视作品,下载了大量的剧集视频,有些文件的命名不规范,就需要重新命名,之前是用的一款 renamer 客户端软件,用起来不太爽就自己做了个 bs 架构的重命名软件并开 ...
- C# 实例解释面向对象编程中的接口隔离原则
在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解.灵活和可维护.这些原则是由美国软件工程师和讲师罗伯特·C·马丁(Robert Cecil Martin)提出的许多原 ...
- Josephus问题(Ⅲ)
题目描述 n个人排成一圈,按顺时针方向依次编号1,2,3-n.从编号为1的人开始顺时针"一二三...."报数,报到m的人退出圈子.这样不断循环下去,圈子里的人将不断减少.最终一定会 ...
- 2022 07 13 第一小组 田龙跃 Java再学习笔记
1.类名命名规则: 只能由数字字母,下划线,美元符号组成(不能以数字开头,尽量不要用下划线开头) 2.注释(养成多写注释的好习惯) 单行注释 // ctrl+/ 多行注释 // ctrl+shirt+ ...
- 基于ABP实现DDD--聚合和聚合根实践
在下面的例子中涉及Repository.Issue.Label.User这4个聚合根,接下来以Issue聚合为例进行分析,其中Issue聚合是由Issue[聚合根].Comment[实体].Iss ...
- 1.JS中变量的重新声明和提升
重新声明 1.允许在程序的任何位置使用 var 重新声明 JavaScript 变量: 实例 var x = 10; // 现在,x 为 10 var x = 6; // 现在,x 为 6 2.在相同 ...