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 ...
随机推荐
- linux下的nginx日志自动备份压缩--日志切割机
部署完毕nginx之后,发现自己的/var/log/nginx/*log的日志不会压缩,一直都是一个文本写日志, 时间久了,日志文件内存过于增加,将会导致在日志添加过程效率降低,延长时间. 默认安装的 ...
- NC13822 Keep In Line
NC13822 Keep In Line 题目 题目描述 又到饭点了,SK同学靠着惯性走到了食堂,但长长的队伍顿时让他失去了食欲.突然,他注意到某个窗口前的队伍里明显存在插队的现象,于是他默默记录下了 ...
- 没有Kubernetes怎么玩Dapr?
Dapr 被设计成一个面向开发者的企业级微服务编程平台,它独立于具体的技术平台,可以运行在"任何地方".Dapr本身并不提供"基础设施(infrastructure)&q ...
- JUC源码学习笔记1——AQS和ReentrantLock
笔记主要参考<Java并发编程的艺术>并且基于JDK1.8的源码进行的刨析,此篇只分析独占模式,后续在ReentrantReadWriteLock和 CountDownLatch中 会重点 ...
- 01. MySQL__数据库分类和介绍
数据库的分类 1. 关系型数据库 以表为数据库存储数据的单位,关系型数据库是经过数学理论验证可以保存现实生活中任何关系型的数据 2. 非关系型数据库 主要应用在一些特定场景,解决某些具体问题比如解决高 ...
- HTML基础学习笔记(一)
简介 基本形式 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <t ...
- mysql语法使用详细代码版
mysql 1.什么是数据库 数据库:(DB,DataBase) 作用:用来存储数据,管理数据.Txt,Excel,word是在数据库出现之前存储数据的. 概念:数据仓库,安装在操作系统上的软件. 数 ...
- Solution -「HNOI2013」消毒
弱化一下,先考虑在二维上解决问题. 题目就转化为:有 \(n\) 个点 \((i, j)\) 需要被覆盖,而我们每次可以选一行或一列去覆盖,求覆盖所有点的最少选择次数. 如果我们对于每一个 \((i, ...
- 在centos7.6上部署前后端分离项目Nginx反向代理vue.js2.6+Tornado5.1.1,使用supervisor统一管理服务
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_102 这一次使用vue.js+tornado的组合来部署前后端分离的web项目,vue.js不用说了,前端当红炸子鸡,泛用性非常广 ...
- fijkplayer问题反馈:暂停时拖动进度光标,在窗口模式与全屏模式间切换后,进度光标不能及时更新、正常跟进
fijkplayer-0.8.4很优秀,造福苍生,非常感谢! 使用fijkplayer-0.8.4开发的过程中遇到以下问题,特此记录.提交上传:https://github.com/befovy/fi ...