AVL Tree
AVL树是由G. M. Adelson-Velsky和E. M. Landis 在1962年发明, 是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
Tips
对于普通的二叉搜索树(BST),增加或删除节点都可能使其退化成链表,时间复杂度就是O(N),AVL在BST的基础上维护了树的平衡,通过树的旋转保持整棵树趋向于一颗满二叉树,使其高度保持在 O(logN)
BST改进
添加节点12,此时这颗树并不平衡。
中序遍历依旧是有序的,但保持了树的平衡,本质上其实是为了减少树的高度
添加导致的失衡
AVL添加节点前都是平衡的,添加节点最坏情况可能会导致其祖先节点都失衡(父节点不会失衡)。
右旋 LL
红色节点为新增节点,添加后此时子树是失衡的,通过以下步骤恢复平衡。
- g.left = p.right
- p.right = g
- 使p成为新的根
注意旋转后需要维护高度和parent的指向。
旋转后子树依旧是有序的
旋转后根节点往上的其他节点并不会失衡,因为添加新节点前AVL永远是平衡的,旋转后子树的高度并不会发生改变,所以添加节点只需要一次的旋转,而删除可能需要 logN 次旋转。
左旋 RR
和LL情况相反
- g.right = p.left
- p.left = g
- 使p成为新的根
注意旋转后需要维护高度和parent的指向。
也依旧有序。
左旋+右旋 LR
需要进行两次旋转,向对p进行右旋,将n旋转上来,再对g进行左旋,此时n成为新的根节点
注意维护高度和parent指向
子树恢复平衡,也依旧有序。
右旋+左旋 RL
和LR差不多,也是通过旋转想办法将n成为根节点。
注意维护高度和parent指向
子树恢复平衡,也依旧有序。
添加后的操作 C++
void afterAdd(Node* cur)
{
//从新增节点的父节点往上
while ((cur = cur->_parent) != nullptr)
{
if (cur->isBalance()) //平衡情况下更新高度信息。
cur->reHight();
else { //只需要一次旋转就可以恢复平衡。
maintain(cur); //调整子树恢复平衡
break;
}
}
}
添加代码 C++
bool put(const K& key, const V& value)
{
if (!_root) {
_root = new Node(key, value);
_size++;
return true;
}
Node* cur = _root;
while (cur)
{
if (cur->_key < key) //大往右
{
if (cur->_right) //新节点都为叶子节点
cur = cur->_right;
else {
Node* newNode = new Node(key, value);
cur->_right = newNode;
newNode->_parent = cur;
afterAdd(newNode); //添加后一路往上更新高度和维持平衡
_size++;
return true;
}
}
else if (cur->_key > key) //小往右
{
if (cur->_left)
cur = cur->_left;
else {
Node* newNode = new Node(key, value);
cur->_left = newNode;
newNode->_parent = cur;
afterAdd(newNode); //添加后一路往上更新高度和维持平衡
_size++;
return true;
}
}
else { //存在直接更新value
cur->_value = value;
return true;
}
}//end of while
return true;
}
删除导致的失衡
删除节点可能导致其父节点,或往上的祖先节点失衡(只会存在一个失衡)。
我们通过旋转可以让失衡的子树恢复了平衡,但可能导致更高层次的节点发生失衡,最坏情况下,每次旋转可能导致所有祖先节点都失衡,最坏logN次的旋转调整。
删除代码 C++
bool remove(const K& key)
{
if (empty()) return false;
//只有根节点
if (_root->_key == key && size() == 1) {
_size = 0;
delete _root, _root = nullptr;
return true;
}
Node* cur = _root;
bool find = false;
while (cur)
{
if (cur->_key < key)
cur = cur->_right;
else if (cur->_key > key)
cur = cur->_left;
else {
find = true;
break;
}
}//end of while
//没找到直接返回
if (!find) {
return false;
}
if (cur->_left && cur->_right) //度为2
{
Node* prev = cur->_left; //找到前驱节点
while (prev && prev->_right)
prev = prev->_right;
cur->_key = prev->_key, cur->_value = prev->_value;
cur = prev;
}
if (cur->_left || cur->_right) //度为1情况
{
Node* parent = cur->_parent;
Node* child = cur->_left ? cur->_left : cur->_right;
parent->_left == cur ? parent->_left = child : parent->_right = child;
child->_parent = parent;
afterRemove(cur);
}
else { //度为0的情况
Node* parent = cur->_parent;
parent->_left == cur ? parent->_left = nullptr : parent->_right = nullptr;
afterRemove(cur);
}
_size--;
delete cur;
return true;
}
完整代码 C++
#include <iostream>
#include <cmath>
#include <queue>
#include <cassert>
using namespace std;
template<class K, class V>
class AVL {
public:
struct Node {
Node(const K& key, const V& value) :
_key(key), _value(value), _parent(nullptr), _left(nullptr), _right(nullptr) {}
Node* tallerChild()
{
size_t left = this->_left->hight();
size_t right = this->_right->hight();
return left < right
? this->_right
: this->_left;
}
size_t hight()
{
return !this ? 0 : this->_hight;
}
bool isBalance()
{
int left = this->_left->hight();
int right = this->_right->hight();
return fabs(left - right) < 2 ? true : false;
}
void reHight()
{
int left = this->_left->hight();
int right = this->_right->hight();
this->_hight = left > right ? left + 1 : right + 1;
}
K _key;
V _value;
Node* _parent;
Node* _left;
Node* _right;
size_t _hight = 1;
};
public:
bool put(const K& key, const V& value)
{
if (!_root) {
_root = new Node(key, value);
_size++;
return true;
}
Node* cur = _root;
while (cur)
{
if (cur->_key < key) //大往右
{
if (cur->_right) //新节点都为叶子节点
cur = cur->_right;
else {
Node* newNode = new Node(key, value);
cur->_right = newNode;
newNode->_parent = cur;
afterAdd(newNode); //添加后一路往上更新高度和维持平衡
_size++;
return true;
}
}
else if (cur->_key > key) //小往右
{
if (cur->_left)
cur = cur->_left;
else {
Node* newNode = new Node(key, value);
cur->_left = newNode;
newNode->_parent = cur;
afterAdd(newNode); //添加后一路往上更新高度和维持平衡
_size++;
return true;
}
}
else { //存在直接更新value
cur->_value = value;
return true;
}
}//end of while
return true;
}
bool remove(const K& key)
{
if (empty()) return false;
//只有根节点
if (_root->_key == key && size() == 1) {
_size = 0;
delete _root, _root = nullptr;
return true;
}
Node* cur = _root;
bool find = false;
while (cur)
{
if (cur->_key < key)
cur = cur->_right;
else if (cur->_key > key)
cur = cur->_left;
else {
find = true;
break;
}
}//end of while
//没找到直接返回
if (!find) {
return false;
}
if (cur->_left && cur->_right) //度为2
{
Node* prev = cur->_left; //找到前驱节点
while (prev && prev->_right)
prev = prev->_right;
cur->_key = prev->_key, cur->_value = prev->_value;
cur = prev;
}
if (cur->_left || cur->_right) //度为1情况
{
Node* parent = cur->_parent;
Node* child = cur->_left ? cur->_left : cur->_right;
parent->_left == cur ? parent->_left = child : parent->_right = child;
child->_parent = parent;
afterRemove(cur);
}
else { //度为0的情况
Node* parent = cur->_parent;
parent->_left == cur ? parent->_left = nullptr : parent->_right = nullptr;
afterRemove(cur);
}
_size--;
delete cur;
return true;
}
void afterRemove(Node* cur) {
while ((cur = cur->_parent) != nullptr)
{
if (cur->isBalance())
cur->reHight();
else {
maintain(cur);
}
}
}
void afterAdd(Node* cur)
{
while ((cur = cur->_parent) != nullptr)
{
if (cur->isBalance())
cur->reHight();
else {
maintain(cur);
break;
}
}
}
bool contains(const K& key)
{
if (empty()) return false;
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
cur = cur->_left;
else if (cur->_key < key)
cur = cur->_right;
else
return true;
}
return false;
}
void maintain(Node* grand)
{
if (!grand) return;
Node* parent = grand->tallerChild();
Node* node = parent ? parent->tallerChild() : nullptr;
if (parent && node && parent == grand->_left)
{
if (node == parent->_left) //LL
right_rotate(grand);
else { //LR
left_rotate(parent);
right_rotate(grand);
}
}
else if (parent && node && parent == grand->_right)
{
if (node == parent->_right) //RR
left_rotate(grand);
else { //RL
right_rotate(parent);
left_rotate(grand);
}
}
}
void left_rotate(Node* cur)
{
Node* parent = cur->_parent;
bool isRoot = (cur == _root) ? true : false;
Node* R = cur->_right;
cur->_parent = R;
cur->_right = R->_left;
if (cur->_right)
cur->_right->_parent = cur;
R->_left = cur;
cur->reHight();
R->reHight();
if (isRoot) {
_root = R;
_root->_parent = nullptr;
}
else {
parent->_left == cur ? parent->_left = R : parent->_right = R;
R->_parent = parent;
}
}
void right_rotate(Node* cur)
{
Node* parent = cur->_parent;
bool isRoot = (cur == _root) ? true : false;
Node* L = cur->_left;
cur->_parent = L;
cur->_left = L->_right;
if (cur->_left)
cur->_left->_parent = cur;
L->_right = cur;
cur->reHight();
L->reHight();
if (isRoot) {
_root = L;
_root->_parent = nullptr;
}
else {
parent->_left == cur ? parent->_left = L : parent->_right = L;
L->_parent = parent;
}
}
size_t size()
{
return _size;
}
bool empty()
{
return _root == nullptr;
}
//private:
Node* _root = nullptr;
size_t _size = 0;
};