二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度
一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:
- 它的左右子树都是AVL树
- 左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1)
上图中的 0,-1,1叫做平衡因子;
平衡因子 = 右子树的高度 - 左子树的高度
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在 ,搜索时间复杂度O(log(2)N);
2.AVL树的实现AVLTree.h
#pragma once #include#include #include using namespace std; template struct AVLTreeNode { AVLTreeNode * _left; AVLTreeNode * _right; AVLTreeNode * _parent; int _bf;//平衡因子 pair _kv; AVLTreeNode(const pair & kv) :_left(nullptr) , _right(nullptr) , _parent(nullptr) , _bf(0) , _kv(kv) {} }; template class AVLTree { typedef AVLTreeNode Node; public: AVLTree() :_root(nullptr) {} void _Destory(Node* root) { if (root == nullptr) { return; } _Destory(root->_left); _Destory(root->_right); delete root; } ~AVLTree() { _Destory(_root); _root = nullptr; } V& operator[](const K& key) { pair ret = Insert(make_pair(key, V())); return ret.first->_kv.second; } pair Insert(const pair & kv) { if (_root == nullptr)//第一次插入 { _root = new Node(kv); return make_pair(_root, true); } Node* cur = _root; Node* parent = nullptr; while (cur)//找到该插入的正确位置 { if (kv.first < cur->_kv.first) { parent = cur; cur = cur->_left; } else if (kv.first > cur->_kv.first) { parent = cur; cur = cur->_right; } else { return make_pair(cur, false); } } cur = new Node(kv); Node* newnode = cur; //判断cur是parent的左边还是右边 if (cur->_kv.first < parent->_kv.first) { parent->_left = cur; cur->_parent = parent; } else { parent->_right = cur; cur->_parent = parent; } //更新平衡因子 //如果出现不平衡 即平衡因子等于2或-2,需要旋转 //当插入一个节点,该节点的所有祖先都需要更新平衡因子 //我们从最近的祖先开始更新 while (cur != _root) { if (cur == parent->_right)//说明右子树变高 { parent->_bf++; } else { parent->_bf--;//左子树变高 } //判断以parent为根节点的这颗子树是否平衡,不平衡就旋转 if (parent->_bf == 0)//不需要在调了 跳出循环 { break; } else if (parent->_bf == 1 || parent->_bf == -1)//说明插入之前是0,曾左右子树同样高,现在左右某一颗子树变高了,继续更新上面祖先的平衡因子 { cur = parent; parent = parent->_parent; } else if (parent->_bf == 2 || parent->_bf == -2)//不平衡了,需要旋转 { if (parent->_bf == 2) { if (cur->_bf == 1)//在较高右子树的右侧插入 { RotateL(parent); } else//在较高右子树的左侧插入 { RotateRL(parent); } } else { if (cur->_bf == -1)//在较高左子树的左侧插入 { RotateR(parent); } else//在较高左子树的右侧插入 { RotateLR(parent); } } break; } else { assert(false); } } return make_pair(newnode, true); } void RotateLR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; int bf = subLR->_bf; RotateL(parent->_left); RotateR(parent); //调平衡因子 if (bf == -1) { subLR->_bf = 0; parent->_bf = 1; subL->_bf = 0; } else if (bf == 1) { subLR->_bf = 0; parent->_bf = 0; subL->_bf = -1; } else if (bf == 0) { subLR->_bf = 0; parent->_bf = 0; subL->_bf = 0; } else { assert(false); } } void RotateRL(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left; int bf = subRL->_bf; RotateR(parent->_right); RotateL(parent); //调平衡因子 if (bf == -1) { subR->_bf = 1; parent->_bf = 0; subRL->_bf = 0; } else if (bf == 1) { subR->_bf = 0; parent->_bf = -1; subRL->_bf = 0; } else if (bf == 0)//subRL就是新增节点 { subR->_bf = 0; parent->_bf = 0; subRL->_bf = 0; } else { assert(false);//理论上不可能出现这种情况 } } void RotateL(Node* parent)//左单旋 { Node* subR = parent->_right; Node* subRL = subR->_left; Node* parentParent = parent->_parent; parent->_right = subRL; if (subRL)//subRL为空就不用给subRL找父母了 { subRL->_parent = parent; } parent->_parent = subR; subR->_left = parent; if (parent == _root)//如果parent是根节点,把根节点改为subR,_root的父母置为nullptr { _root = subR; _root->_parent = nullptr; } else//parent不是根节点 { //判断parent是parentParent的左还是右 if (parentParent->_left == parent) { parentParent->_left = subR; } else { parentParent->_right = subR; } subR->_parent = parentParent; } //旋转之后,subR和parent的平衡因子都为0 subR->_bf = 0; parent->_bf = 0; } void RotateR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right; Node* parentParent = parent->_parent; parent->_left = subLR; if (subLR) { subLR->_parent = parent; } parent->_parent = subL; subL->_right = parent; if (parent == _root) { _root = subL; _root->_parent = nullptr; } else { if (parent == parentParent->_left) { parentParent->_left = subL; } else { parentParent->_right = subL; } subL->_parent = parentParent; } subL->_bf = 0; parent->_bf = 0; } //中序遍历 void _InOrder(Node* root) { if (root == nullptr) { return; } _InOrder(root->_left); cout << root->_kv.first << ":" << root->_kv.second << endl; _InOrder(root->_right); } void InOrder() { _InOrder(_root); } //查找 Node* Find(const K& key) { Node* cur = _root; while (cur) { if (cur->_kv.first > key) { cur = cur->_left; } else if (cur->_kv.first < key) { cur = cur->_right; } else { return cur; } } return nullptr; } //求高度 int _Height(Node* root) { if (root == nullptr) { return 0; } int left = _Height(root->_left); int right = _Height(root->_right); return left > right ? 1 + left : 1 + right; } int Height() { return _Height(_root); } //判断是否为AVL树 bool _isBalance(Node* root) { if (root == nullptr) { return true; } int left = _Height(root->_left); int right = _Height(root->_right); //检查平衡因子是否异常 if (right - left != root->_bf) { cout << "平衡因子异常" << root->_kv.first << endl; return false; } return abs(left - right) < 2 && _isBalance(root->_left) && _isBalance(root->_right); } bool isAVLTree() { return _isBalance(_root); } private: Node* _root; };
test.cpp
#include "AVLTree.h" #include3.AVL树的性能void TestAVLTree() { //int a[] = { 1,3,5, 7,9}; //int a[] = {16, 3, 7, 11, 9, 26, 18, 14, 15}; int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 }; AVLTree t; for (auto e : a) { t.Insert(make_pair(e, e)); } t.InOrder(); cout << t.isAVLTree() << endl; t[3] *= 10; t[4] *= 10; t[5] *= 10; t.InOrder(); AVLTree dict; dict.Insert(make_pair("happy", "")); dict.Insert(make_pair("hello", "")); dict.InOrder(); dict["happy"] = "快乐的"; dict["hello"] = "你好"; dict.InOrder(); dict["happy"] += ",开心的"; dict.InOrder(); } int main() { TestAVLTree(); return 0; }
} t.InOrder(); cout << t.isAVLTree() << endl; t[3] *= 10; t[4] *= 10; t[5] *= 10; t.InOrder(); AVLTreedict; dict.Insert(make_pair("happy", "")); dict.Insert(make_pair("hello", "")); dict.InOrder(); dict["happy"] = "快乐的"; dict["hello"] = "你好"; dict.InOrder(); dict["happy"] += ",开心的"; dict.InOrder();
}
int main()
{
TestAVLTree();
return 0;
}
# 3.AVL树的性能 AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样可以保证查询时高效的时间复杂度,即 O(log(2)N)。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。



