二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下
。因此,两位俄罗斯的数学家
G.M.Adelson-Velskii和E.M.Landis在1962年
发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1
(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
两种计算平衡因子的方法
法一:节点的左子树高度减右子树高度
法二:节点的右子树高度减左子树高度
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在
O(log2n)O(log_2 n)O(log2n),搜索时间复杂度O(log2nlog_2 nlog2n)。
实现的是KV模型
平衡因子的计算方法由第二种方法实现
分为三个步骤
1.按照二叉搜索树的方式插入新节点
2.更新整体节点的平衡因子
3.更新平衡因子的过程中判断是否需要旋转
bool Insert(const pair& kv)
{Node* parent = nullptr;Node* cur = _root;//如果根为空if (_root == nullptr){_root = new Node(kv);return true;}//寻找插入位置while (cur){//如果要插入的值比cur的值小if (cur->_kv.first > kv.first){//往左找parent = cur;cur = cur->_left;}//如果要插入的值比cur的值大else if (cur->_kv.first < kv.first){//往右找parent = cur;cur = cur->_right;}//如果相等就不再插入else{return false;}}//插入Node* newnode = new Node(kv);cur = newnode;if (parent->_kv.first > kv.first){parent->_left = newnode;newnode->_parent = parent;//父母节点更新平衡因子parent->_bf--;}else{parent->_right = newnode;newnode->_parent = parent;//父母节点更新平衡因子parent->_bf++;}
}
更新整体节点的平衡因子过程中分三种情况:
1.首先在插入的过程中,更新插入节点的父母节点的平衡因子
2.更新以后判断父母节点的平衡因子
(1)更新后父母节点的平衡因子是0
停止更新,说明更新前父母节点的平衡因子是1或者-1,现在变成0也表明了父母节点的左右子树中高度矮的子树插入了新节点
if (parent->_bf == 0){break;}
(2)更新后父母节点的平衡因子是1或者-1
继续向上更新, 说明更新前父母节点的平衡因子是0,现在是1或者-1,也表明父母节点的左右子树中的一颗树的高度变高了。父母节点所在的子树高度也变高了。
else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;//继续向上更新parent = parent->_parent;if (parent){if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}}}
(3)更新后父母节点的平衡因子是2或者-2
说明父母节点所在的子树已经不平衡了需要旋转处理
else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == -2 && cur->_bf == -1){//右单旋RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == 1){//左单旋RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){//左右双旋RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){//右左双旋RotateRL(parent);}else{//不可能的情况assert(false);}break;}
整体的插入代码
//更新整体平衡因子
while (parent)
{if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;//继续向上更新parent = parent->_parent;if (parent){if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}}}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == -2 && cur->_bf == -1){//右单旋RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == 1){//左单旋RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){//左右双旋RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){//右左双旋RotateRL(parent);}else{//不可能的情况assert(false);}break;}else{//不可能的情况assert(false);}
}
旋转处理是为了处理保证二叉搜索树处于平衡状态,每当二叉搜索树不平衡时就会触发旋转。
旋转又分4种分别处理4种不平衡的情况。
void RotateR(Node* parent)
{//要调整的节点Node* sub = parent;//要调整的节点的左孩子Node* subL = parent->_left;//要调整的节点的左孩子的右孩子Node* subLR = subL->_right;//要调整的节点的父母Node* subparent = sub->_parent;//重新链接关系if (subLR)subLR->_parent = sub;sub->_left = subLR;sub->_parent = subL;subL->_right = sub;subL->_parent = subparent;if (_root == sub){_root = subL;}else{if (subparent->_left == sub){subparent->_left = subL;}else{subparent->_right = subL;}}subL->_bf = sub->_bf = 0;
}
void RotateL(Node* parent)
{//要调整的节点Node* sub = parent;//要调整的节点的右孩子Node* subR = parent->_right;//要调整的节点的有孩子的左孩子Node* subRL = subR->_left;//要调整的节点的父母Node* subparent = sub->_parent;//重新链接关系if (subRL)subRL->_parent = sub;sub->_right = subRL;sub->_parent = subR;subR->_left = sub;subR->_parent = subparent;if (_root == sub){_root = subR;}else{if (subparent->_left == sub){subparent->_left = subR;}else{subparent->_right = subR;}}subR->_bf = sub->_bf = 0;
}
void RotateLR(Node* parent)
{Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);if (bf == -1){parent->_bf = 1;subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subLR->_bf = 0;subL->_bf = -1;}else if (bf == 0){parent->_bf = 0;subLR->_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){parent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}else if (bf == 1){parent->_bf = -1;subRL->_bf = 0;subR->_bf = 0;}else if (bf == 0){parent->_bf = 0;subRL->_bf = 0;subR->_bf = 0;}else{assert(false);}}
AVL.h
#pragma once
#include
namespace lzf
{templatestruct AVLTreeNode{AVLTreeNode* _left;//该节点的左孩子AVLTreeNode* _right;//该节点的右孩子AVLTreeNode* _parent;//该节点的双亲节点pair _kv;//该节点的kvint _bf;//该节点的平衡因子//构造函数AVLTreeNode(const pair& kv):_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0),_kv(kv){}};templateclass AVLTree{typedef AVLTreeNode Node;public:AVLTree():_root(nullptr){}bool Insert(const pair& kv){Node* parent = nullptr;Node* cur = _root;//如果根为空if (_root == nullptr){_root = new Node(kv);return true;}//寻找插入位置while (cur){//如果要插入的值比cur的值小if (cur->_kv.first > kv.first){//往左找parent = cur;cur = cur->_left;}//如果要插入的值比cur的值大else if (cur->_kv.first < kv.first){//往右找parent = cur;cur = cur->_right;}//如果相等就不再插入else{return false;}}//插入Node* newnode = new Node(kv);cur = newnode;if (parent->_kv.first > kv.first){parent->_left = newnode;newnode->_parent = parent;//父母节点更新平衡因子parent->_bf--;}else{parent->_right = newnode;newnode->_parent = parent;//父母节点更新平衡因子parent->_bf++;}//更新整体平衡因子while (parent){if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;//继续向上更新parent = parent->_parent;if (parent){if (parent->_left == cur){parent->_bf--;}else{parent->_bf++;}}}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == -2 && cur->_bf == -1){//右单旋RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == 1){//左单旋RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){//左右双旋RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){//右左双旋RotateRL(parent);}else{//不可能的情况assert(false);}break;}else{//不可能的情况assert(false);}}return true;}void InOrder(){_InOrder(_root);}bool IsbalanceTree(){return _IsbalanceTree(_root);}private:void RotateR(Node* parent){//要调整的节点Node* sub = parent;//要调整的节点的左孩子Node* subL = parent->_left;//要调整的节点的左孩子的右孩子Node* subLR = subL->_right;//要调整的节点的父母Node* subparent = sub->_parent;//重新链接关系if (subLR)subLR->_parent = sub;sub->_left = subLR;sub->_parent = subL;subL->_right = sub;subL->_parent = subparent;if (_root == sub){_root = subL;}else{if (subparent->_left == sub){subparent->_left = subL;}else{subparent->_right = subL;}}subL->_bf = sub->_bf = 0;}void RotateL(Node* parent){//要调整的节点Node* sub = parent;//要调整的节点的右孩子Node* subR = parent->_right;//要调整的节点的有孩子的左孩子Node* subRL = subR->_left;//要调整的节点的父母Node* subparent = sub->_parent;//重新链接关系if (subRL)subRL->_parent = sub;sub->_right = subRL;sub->_parent = subR;subR->_left = sub;subR->_parent = subparent;if (_root == sub){_root = subR;}else{if (subparent->_left == sub){subparent->_left = subR;}else{subparent->_right = subR;}}subR->_bf = sub->_bf = 0;}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);if (bf == -1){parent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}else if (bf == 1){parent->_bf = -1;subRL->_bf = 0;subR->_bf = 0;}else if (bf == 0){parent->_bf = 0;subRL->_bf = 0;subR->_bf = 0;}else{assert(false);}}void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;RotateL(parent->_left);RotateR(parent);if (bf == -1){parent->_bf = 1;subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subLR->_bf = 0;subL->_bf = -1;}else if (bf == 0){parent->_bf = 0;subLR->_bf = 0;subL->_bf = 0;}else{assert(false);}}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}int Hegiht(Node* root){if (root == nullptr){return 0;}return Hegiht(root->_left) > Hegiht(root->_right) ? Hegiht(root->_left) + 1 : Hegiht(root->_right) + 1;}bool _IsbalanceTree(Node* root){if (root == nullptr){return true;}int leftHeight = Hegiht(root->_left);int rightHeight = Hegiht(root->_right);if ((rightHeight - leftHeight) != root->_bf){cout << root->_kv.first << "现在bf是:" << root->_bf <<" ";cout << "应该是:" << (rightHeight - leftHeight) << endl;return false;}return abs(rightHeight - leftHeight) < 2&& _IsbalanceTree(root->_left)&& _IsbalanceTree(root->_right);}private:Node* _root;};void Test_AVLTree1(){AVLTree tree;tree.Insert(make_pair(5, 5));tree.Insert(make_pair(3, 3));tree.Insert(make_pair(8, 8));tree.Insert(make_pair(4, 4));tree.Insert(make_pair(6, 6));tree.Insert(make_pair(2, 2));tree.Insert(make_pair(7, 7));tree.InOrder();cout << tree.IsbalanceTree();}void Test_AVLTree2(){AVLTree t;//int a[] = {5,4,3,2,1,0};//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };for (auto e : a){t.Insert(make_pair(e, e));cout << "Insert" << e << ":" << t.IsbalanceTree() << endl;}t.InOrder();cout << t.IsbalanceTree() << endl;}}