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 ...
随机推荐
- [零基础学IoT Pwn] 复现Netgear WNAP320 RCE
[零基础学IoT Pwn] 复现Netgear WNAP320 RCE 0x00 前言: 这是[零基础学IoT Pwn]的第二篇,上篇我们搭好了仿真环境后,模拟运行了Netgear WNAP320固件 ...
- 更好的Android多线程下载框架
/** * 作者:Pich * 原文链接:http://me.woblog.cn/ * QQ群:129961195 * Github:https://github.com/lifengsofts */ ...
- 【实操填坑】在树莓派上编译 EtherCAT IgH Master 主站程序
官网下载地址:https://etherlab.org/download/ethercat/ (可list查看文件列表)https://etherlab.org/download/ethercat/ ...
- NFS配置-实现多服务器共享目录
NFS网络文件系统 为什么要用NFS? 前端所有的应用服务器接收到用户上传的图片.文件.视频,都会统一放到后端的存储上.共享存储的好处:方便数据的查找与取出,缺点:存储服务器压力大,坏了丢失全部数据. ...
- TFrecord写入与读取
Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializi ...
- 【Java线程池】 java.util.concurrent.ThreadPoolExecutor 分析
线程池概述 线程池,是指管理一组同构工作线程的资源池. 线程池在工作队列(Work Queue)中保存了所有等待执行的任务.工作者线程(Work Thread)会从工作队列中获取一个任务并执行,然后返 ...
- 如何有效地开发 Jmix 扩展组件
扩展组件的概念在使用 Jmix 框架开发中扮演着非常重要的角色.我们将在本文探索什么是扩展组件以及 Jmix Studio 在扩展组件开发和应用程序模块化方面能给开发者带来什么帮助. Jmix 中的扩 ...
- WPF 截图控件之移除控件(九)「仿微信」
WPF 截图控件之移除控件(九)「仿微信」 WPF 截图控件之移除控件(九)「仿微信」 作者:WPFDevelopersOrg 原文链接: https://github.com/WPFDevelope ...
- MySQL 启停过程了解一二
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. GreatSQL是MySQL的国产分支版本,使用上与MySQL一致. 前言 你知道MySQL启停都做了些什么吗? 启动的时 ...
- ROS机械臂 Movelt 学习笔记5 | MoveIt Commander Scripting
前一讲python接口中提到moveit_commander 包.这个包提供了用于运动规划.笛卡尔路径计算以及拾取和放置的接口. moveit_commander 包还包括一个命令行接口程序movei ...