目录
对于普通二叉搜索树,如果在数据有序或者接近有序时插入删除,二叉搜索树会退化成单支树,也就是类似单链表的结构;因此为了避免普通二叉搜索树的高度增长过快,降低二叉搜索树的效率与性能。
规定在插入和删除二叉搜索树的结点时,要保证任意结点的左右子树高度差的绝对值不超过1,我们将这样特殊的二叉搜索树称为AVL树(平衡二叉树)。每一个结点中有记录其左右子树高度差的平衡因子,也即平衡因子的值只可能是-1,0,1。(1如果某结点的左子树高度比右子树高度高一则平衡因子为-1,如果某结点的左子树高度比右子树高度低一则平衡因子为1,如果某结点的左子树高度与右子树高度一样则平衡因子为0)。
AVL树有以下性质:
1,每个结点的左右子树都是AVL树
2,左子树与右子树的高度差只能为-1,0,1(规定平衡因子等于右子树的高度减左子树的高度)
3,如果AVL树非常平衡,则整体结构接近满二叉树,所以当结点为N个时,其高度为log(2)N
为了便于更新平衡因子与旋转处理AVL树的链式结构采用三叉链,也就是AVL树的每个结点都包含:双亲结点地址,左孩子地址,右孩子地址,平衡因子,KV数据。
第一步:按照二叉搜索树的插入操作进行新结点的插入,但需要注意的是要将新插入结点中的_parent指向改为其双亲。
第二步:更新平衡因子,从插入结点的双亲开始往上更新;如果插入的结点是双亲的右孩子则双亲的平衡因子--,如果插入的结点是双亲的左孩子则双亲的平衡因子++;更新过的平衡因子有三种情况:
1,如果平衡因子变为0,则说明原来的平衡因子为-1或者1,也就是原来左右子树的高度差绝对值为1,经过插入新结点,使该结点的左右子树达到平衡,所以无须继续往上更新平衡因子。
2,如果平衡因子变为-1或者1,则说明原来的平衡因子为0,也就是原来左右子树的高度一致,经过插入新结点,使该结点的左右子树的高度差绝对值变为1,所以需要继续往上更新平衡因子。
3,如果平衡因子变为-2或者2,则说明原来的平衡因子为-1或者1,也就是原来左右子树高度差绝对值为1,经过插入新结点,使该结点的左右子树高度差绝对值为2,造成不满足AVL树性质要求需要进行旋转处理。
第三步:旋转处理,使不平衡的AVL树变为平衡的AVL树;造成平衡的AVL树变为不平衡的AVL树的原因有4种,也就是说使不平衡的AVL树变为平衡的AVL树的旋转处理方式也有4种,每一种原因对应一种旋转处理方式。
在A结点的左孩子B的左子树上插入新结点,导致以A为根的子树失去平衡(左子树比右子树高),需要进行右旋转处理
右旋转的具体操作:先让B结点的_right指向A结点,再让A结点的_left指向原B结点的右子树b。
在A结点的右孩子B的右子树上插入新结点,导致以A为根的子树失去平衡(左子树比右子树低),需要进行左旋转处理。
左旋转的具体操作:先让B结点的_left指向A结点,再让A结点的_right指向原B结点的左子树b。
由于在A的左孩子B的右子树上插入新结点,A的平衡因子由-1变为-2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先左旋转再右旋转。左旋转是以B结点为轴,右旋转是以A结点为轴。
具体操作:先将A结点的左孩子B的右子树的根节点C向左上旋转提升到B结点的位置,然后把该C结点向右上旋转提升到A结点的位置。
- // 左右旋
- void RotateLR(Node* parrnt)
- {
- Node* subL = parrnt->_left;
- Node* subLR = subL->_right;
- short bf = subLR->_bf;
-
- RotateL(parrnt->_left);
- RotateR(parrnt);
-
- if (bf == 1)
- {
- subLR->_bf = 0;
- subL->_bf = -1;
- parrnt->_bf = 0;
- }
- else if (bf == -1)
- {
- subLR->_bf = 0;
- subL->_bf = 0;
- parrnt->_bf = 1;
- }
- else if(bf==0)
- {
-
- subLR->_bf = 0;
- subL->_bf = 0;
- parrnt->_bf = 0;
- }
- else
- {
- assert(false);
- }
- }
由于在A的右孩子B的左子树上插入新结点,A的平衡因子由1变为2,导致以A为根的子树失去平衡,需要进行两次旋转操作,先右旋转在左旋转。右旋转是以B结点为轴,左旋转是以A结点为轴。
具体操作:先将A结点的右孩子B的左子树的根节点C向右上旋转提升到B结点的位置,然后把该C结点向左上旋转提升到A结点的位置。
- // 右左旋
- void RotateRL(Node* parent)
- {
- Node* subR = parent->_right;
- Node* subRL = subR->_left;
- short bf = subRL->_bf;
-
- RotateR(parent->_right);
- RotateL(parent);
-
- if (bf == 1)
- {
- subRL->_bf = 0;
- subR->_bf = 0;
- parent->_bf = -1;
- }
- else if (bf==-1)
- {
- subRL->_bf = 0;
- subR->_bf = 1;
- parent->_bf = 0;
- }
- else if(bf==0)
- {
- subRL->_bf = 0;
- subR->_bf = 0;
- parent->_bf = 0;
- }
- else
- {
- assert(false);
- }
- }
第一步:先找到要删除的结点
第二步:按照要删除结点的类型进行分类删除:1,左子树为空 2,右子树为空 3,左右子树都为空 4,左右子树都不为空
第三步:更新平衡因子。如果删除的结点在其双亲的左边则双亲的平衡因子++,如果删除的结点在其双亲结点的右边则双亲的平衡因子--。
1,如果更新后parent->_bf==0,说明parent->_bf原来是-1或者1,把高的那边删除掉了,高度变小了,继续往上更新。
2,如果更新后parent->_bf==-1或者parenr->_bf==1,说明parent->_bf原来是0,删除了其左右结点其中的一个,高度没有变,不需要继续往上更新。
3,如果更新后parent->_bf==-2或者parenr->_bf==2,说明AVL树不平衡,需要旋转处理。
第四步:旋转处理。
// 旋转规则(有四种情况):
// firstDepth是parent高度最高的孩子结点,secondDepth是firstDepth高度最后的结点
// 1,如果first是parent的左孩子,second是first的左孩子---右旋转
// 2,如果first是parent的左孩子,second是first的右孩子---左右双旋// 3,如果first是parent的右孩子,second是first的右孩子---左旋转
// 4,如果first是parent的右孩子,second是first的左孩子---右左双旋
- // 无参构造
- AVLTree()
- :_root(nullptr)
- {
-
- }
- // 拷贝构造
- Node* _CopyAVLTree(Node* root, Node* parent)
- {
- if (root == nullptr)
- {
- return nullptr;
- }
-
- Node* newNode = new Node(root->_kv);
- newNode->_bf = root->_bf;
- newNode->_parent = parent;
- newNode->_left = _CopyAVLTree(root->_left,newNode);
- newNode->_right = _CopyAVLTree(root->_right,newNode);
-
- return newNode;
- }
-
- AVLTree(const AVLTree& t)
- {
- _root=_CopyAVLTree(t._root, nullptr);
- }
- //析构
- ~AVLTree()
- {
- _Destroy(_root);
- _root = nullptr;
- }
-
- //销毁
- void _Destroy(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
- _Destroy(root->_left);
- _Destroy(root->_right);
- delete root;
- }
- AVLTree& operator=(AVLTree t)
- {
- swap(_root, t._root);
- return *this;
- }
- V& operator[](const K& key)
- {
- pair
bool> ret = Insert(make_pair(key,V())); - return (ret.first)->_kv.second;
- }
- void InOrder()
- {
- _InOrder(_root);
- cout << endl;
- }
- bool IsAVLTree()
- {
- return _IsAVLTree(_root);
- }
- // .hpp
- #pragma once
- #include
- #include
- using namespace std;
-
- template <class K,class V>
- struct AVLTreeNode
- {
- short _bf; // 平衡因子---记录其左右子树的高度差(右子树高度减左子树高度)
-
- struct AVLTreeNode
* _parent; // 记录其双亲的地址 - struct AVLTreeNode
* _left; // 记录其左孩子的地址 - struct AVLTreeNode
* _right; // 记录其右孩子的地址 -
- pair
_kv; // kv值 -
- AVLTreeNode(const pair
& kv) - :_bf(0)
- ,_parent(nullptr)
- ,_left(nullptr)
- ,_right(nullptr)
- ,_kv(kv)
- {
-
- }
- };
-
- template <class K,class V>
- class AVLTree
- {
- typedef struct AVLTreeNode
Node; - private:
- Node* _root;
-
- // 左旋转---左子树低
- void RotateL(Node* parent) // parent是平衡因子为-2或者2的结点
- {
- Node* parentParent = parent->_parent; // 记录其双亲
- Node* subR = parent->_right; // 记录其右孩子
- Node* subRL = subR->_left; // 记录其右孩子的左孩子
-
- // 让subR的左孩子指向parent,parent的双亲指向subR
- subR->_left = parent;
- parent->_parent = subR;
-
- // 让parent的右孩子指向subR的左孩子
- parent->_right = subRL;
- if (subRL) // 如果subRL不为空,则让subR的左孩子的_parent指向parent
- {
- subRL->_parent = parent;
- }
-
- // 更新parent的双亲结点中的左孩子或者右孩子指向,并更新subR的_parent的指向
- if (parent == _root)
- {
- _root = subR;
- subR->_parent = nullptr;
- }
- else
- {
- if (parentParent->_left == parent)
- {
- parentParent->_left = subR;
- }
- else if(parentParent->_right==parent)
- {
- parentParent->_right = subR;
- }
- subR->_parent = parentParent;
- }
-
- // 更新旋转处理后的平衡因子
- parent->_bf = 0;
- subR->_bf = 0;
- }
-
- // 右旋转
- void RotateR(Node* parent) // parent是平衡因子为-2或者2的结点
- {
- Node* parentParent = parent->_parent; // 记录其双亲
- Node* subL = parent->_left; // 记录其左孩子
- Node* subLR = subL->_right; // 记录其左孩子的右孩子
-
- // parent的双亲指向subL,subL的右孩子指向parent
- parent->_parent = subL;
- subL->_right = parent;
-
- // parent的左孩子指向subL的右孩子
- parent->_left = subLR;
- if (subLR) // 如果subLR不为空,则让subLR的双亲指向parent
- {
- subLR->_parent = parent;
- }
-
- if (_root == parent) // parent的双亲为空则说明parent是整棵树的根节点
- {
- _root = subL; // 让subL当整棵树的根节点
- subL->_parent = nullptr; // 并让subL的双亲指向空
- }
- else // 否则parent是某棵子树的根节点,更新parentParent左孩子或者右孩子的指向
- {
- if (parentParent->_left == parent)
- {
- parentParent->_left = subL;
- }
- else
- {
- parentParent->_right = subL;
- }
- subL->_parent = parentParent; // 更新subL双亲的指向
- }
-
- parent->_bf = subL->_bf = 0; // 经过旋转更新平衡因子
- }
-
- // 左右旋
- void RotateLR(Node* parrnt)
- {
- Node* subL = parrnt->_left;
- Node* subLR = subL->_right;
- short bf = subLR->_bf;
-
- RotateL(parrnt->_left);
- RotateR(parrnt);
-
- if (bf == 1)
- {
- subLR->_bf = 0;
- subL->_bf = -1;
- parrnt->_bf = 0;
- }
- else if (bf == -1)
- {
- subLR->_bf = 0;
- subL->_bf = 0;
- parrnt->_bf = 1;
- }
- else if(bf==0)
- {
-
- subLR->_bf = 0;
- subL->_bf = 0;
- parrnt->_bf = 0;
- }
- else
- {
- assert(false);
- }
- }
-
- // 右左旋
- void RotateRL(Node* parent)
- {
- Node* subR = parent->_right;
- Node* subRL = subR->_left;
- short bf = subRL->_bf;
-
- RotateR(parent->_right);
- RotateL(parent);
-
- if (bf == 1)
- {
- subRL->_bf = 0;
- subR->_bf = 0;
- parent->_bf = -1;
- }
- else if (bf==-1)
- {
- subRL->_bf = 0;
- subR->_bf = 1;
- parent->_bf = 0;
- }
- else if(bf==0)
- {
- subRL->_bf = 0;
- subR->_bf = 0;
- parent->_bf = 0;
- }
- else
- {
- assert(false);
- }
- }
-
- // parent为删除结点的双亲,child为删除的结点
- void UpdateBF(Node* parent,Node* child)
- {
- while (parent != nullptr)
- {
- if (parent->_left == child)
- {
- parent->_bf++;
- }
- else if (parent->_right == child)
- {
- parent->_bf--;
- }
-
- // 检查平衡因子是否异常
- if (parent->_bf == 0)
- {
- child = parent;
- parent = parent->_parent;
- }
- else if (parent->_bf == 1 || parent->_bf == -1)
- {
- break;
- }
- else if (parent->_bf == 2 || parent->_bf == -2)
- {
- // 求出平衡因子异常结点的左右子树中高的那一棵子树
- Node* firstDepth = parent->_left;
- int maxDepth = AVLTreeDepth(parent->_left);
- int minDepth = AVLTreeDepth(parent->_right);
- if (maxDepth < minDepth)
- {
- firstDepth = parent->_right;
- }
-
- // 求出firstDepth结点的左右子树中高的那一棵子树
- Node* secondDepth = firstDepth->_left;
- maxDepth = AVLTreeDepth(firstDepth->_left);
- minDepth = AVLTreeDepth(firstDepth->_right);
- if (maxDepth < minDepth)
- {
- secondDepth = firstDepth->_right;
- }
-
- // 旋转规则(有四种情况):
- // firstDepth是parent高度最高的孩子结点,secondDepth是firstDepth高度最后的结点
- // 1,如果first是parent的左孩子,second是first的左孩子---右旋转
- // 2,如果first是parent的左孩子,second是first的右孩子---左右双旋
- // 3,如果first是parent的右孩子,second是first的右孩子---左旋转
- // 4,如果first是parent的右孩子,second是first的左孩子---右左双旋
- if (parent->_left == firstDepth)
- {
- if (firstDepth->_left == secondDepth)
- {
- RotateR(parent);
- }
- else if (firstDepth->_right == secondDepth)
- {
- RotateLR(parent);
- }
- }
- else if (parent->_right == firstDepth)
- {
- if (firstDepth->_left == secondDepth)
- {
- RotateRL(parent);
- }
- else if (firstDepth->_right == secondDepth)
- {
- RotateL(parent);
- }
- }
- break;
- }
- else
- {
- assert(false);
- }
- }
- }
-
- void _InOrder(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
-
- _InOrder(root->_left);
-
- cout << " K:" << root->_kv.first << " V:" << root->_kv.second << " bf:" << root->_bf <
-
- _InOrder(root->_right);
- }
-
- // 判断是否为AVL树
- bool _IsAVLTree(Node* root)
- {
- if (root == nullptr)
- {
- return true;
- }
-
- int left = AVLTreeDepth(root->_left);
- int right = AVLTreeDepth(root->_right);
-
- return abs(left - right) < 2 && _IsAVLTree(root->_left) && _IsAVLTree(root->_right);
- }
-
- // 拷贝构造
- Node* _CopyAVLTree(Node* root, Node* parent)
- {
- if (root == nullptr)
- {
- return nullptr;
- }
-
- Node* newNode = new Node(root->_kv);
- newNode->_bf = root->_bf;
- newNode->_parent = parent;
- newNode->_left = _CopyAVLTree(root->_left,newNode);
- newNode->_right = _CopyAVLTree(root->_right,newNode);
-
- return newNode;
- }
-
- //销毁
- void _Destroy(Node* root)
- {
- if (root == nullptr)
- {
- return;
- }
- _Destroy(root->_left);
- _Destroy(root->_right);
- delete root;
- }
-
- public:
- AVLTree()
- :_root(nullptr)
- {
-
- }
-
- AVLTree(const AVLTree& t)
- {
- _root=_CopyAVLTree(t._root, nullptr);
- }
-
- ~AVLTree()
- {
- _Destroy(_root);
- _root = nullptr;
- }
-
- V& operator[](const K& key)
- {
- pair
bool> ret = Insert(make_pair(key,V())); - return (ret.first)->_kv.second;
- }
-
- AVLTree& operator=(AVLTree t)
- {
- swap(_root, t._root);
- return *this;
- }
-
- pair
bool > Insert(const pair& kv) - {
- if (_root == nullptr) // 若AVL为空树,则直接插入
- {
- _root = new Node(kv);
- return make_pair(_root,true);
- }
-
- Node* prev = nullptr; // 记录插入结点所在路径的最后一个结点
- Node* curr = _root; // 引导prev走到最后一个结点
-
- // 寻找插入位置
- while (curr)
- {
- if (curr->_kv.first > kv.first) // 要插入的值比较小,往左走
- {
- prev = curr;
- curr = curr->_left;
- }
- else if (curr->_kv.first < kv.first) // 要插入的值比根结点的值大,往右走
- {
- prev = curr;
- curr = curr->_right;
- }
- else // 要插入的值比根结点的值大,则插入失败
- {
- return make_pair(curr,false);
- }
- }
-
- // 开始插入
- curr = new Node(kv);
- Node* ret = curr;
- if (prev->_kv.first > kv.first) // 左插入
- {
- prev->_left = curr;
- curr->_parent = prev; //
- }
- else if (prev->_kv.first < kv.first) // 右插入
- {
- prev->_right = curr;
- curr->_parent = prev; //
- }
-
- // 更新平衡因子---将新插入结点curr的祖先的平衡因子更新
- // while(curr!=_root)
- while (prev != nullptr)
- {
- if (prev->_left == curr)
- {
- prev->_bf--; // 如果是往其左子树插入,则_bf--;
- }
- else if (prev->_right == curr)
- {
- prev->_bf++; // 如果是往其右子树插入,则_bf++;
- }
-
- if (prev->_bf == 0) // 左右子树达到平衡,不需要继续往上更新平衡因子
- {
- break;
- }
- else if (prev->_bf == 1 || prev->_bf == -1) // 需要继续往上更新平衡因子
- {
- curr = prev;
- prev = prev->_parent;
- }
- else if (prev->_bf == 2 || prev->_bf == -2) // 左右子树不平衡,需要继续旋转调整
- {
- if (prev->_bf == 2)
- {
- if (curr->_bf == 1) // 右子树高---右结点的右子树上插入
- {
- RotateL(prev); // 左旋转
- }
- else if (curr->_bf == -1) // 右子树高---右结点的左子树上插入
- {
- RotateRL(prev); // 先右旋再左旋
- }
- }
- else
- {
- if (curr->_bf == 1) // 左子树高---左结点的右子树上插入
- {
- RotateLR(prev); // 先左旋再右旋
- }
- else if (curr->_bf == -1) // 左子树高---左结点的左子树上插入
- {
- RotateR(prev);
- }
- }
- break;
- }
- else
- {
- assert(false);
- }
- }
- return make_pair(ret, true);
- }
-
- bool Erase(const pair
& kv) - {
- if (_root == nullptr)
- {
- return false;
- }
-
- Node* prev = _root;
- Node* curr = _root;
-
- while (curr)
- {
- if (curr->_kv.first > kv.first)
- {
- prev = curr;
- curr = curr->_left;
- }
- else if (curr->_kv.first < kv.first)
- {
- prev = curr;
- curr = curr->_right;
- }
- else
- {
- if (curr->_left == nullptr)
- {
- if (prev == _root)
- {
- _root = curr->_right;
- if (curr->_right)
- {
- curr->_right->_parent = _root;
- }
- delete curr;
- return true;
- }
- else
- {
- UpdateBF(prev, curr);
-
- if (prev->_left == curr)
- {
- prev->_left = curr->_right;
- if (curr->_right)
- {
- curr->_right->_parent = prev->_left;
- }
- }
- else
- {
- prev->_right = curr->_right;
- if (curr->_right)
- {
- curr->_right->_parent = prev->_right;
- }
- }
- delete curr;
- return true;
- }
-
- }
- else if (curr->_right == nullptr)
- {
- if (prev == _root)
- {
- _root = curr->_left;
- if (curr->_left)
- {
- curr->_left->_parent = _root;
- }
- delete curr;
- return true;
- }
- else
- {
- UpdateBF(prev, curr);
- if (prev->_left == curr)
- {
- prev->_left = curr->_left;
- if (curr->_left)
- {
- curr->_left->_parent = prev->_left;
- }
- }
- else
- {
- prev->_right = curr->_left;
- if (curr->_left)
- {
- curr->_left->_parent = prev->_right;
- }
- }
- delete curr;
- return true;
- }
-
- }
- else
- {
- Node* min = curr->_right;
- while (min->_left)
- {
- min = min->_left;
- }
- pair
tmp = min->_kv; - Erase(tmp);
- curr->_kv = tmp;
- return true;
- }
- }
- }
-
- return false;
- }
-
- void InOrder()
- {
- _InOrder(_root);
- cout << endl;
- }
-
- Node* Find(const K& key)
- {
- Node* curr = _root;
- while (curr)
- {
- if (curr->_kv.first > key)
- {
- curr = curr->_left;
- }
- else if (curr->_kv.first < key)
- {
- curr = curr->_right;
- }
- else
- {
- return curr;
- }
- }
- return nullptr;
- }
-
- int AVLTreeDepth(Node* root)
- {
- if (root == nullptr)
- {
- return 0;
- }
-
- int leftDepth = AVLTreeDepth(root->_left);
- int rightDepth = AVLTreeDepth(root->_right);
-
- return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;
- }
-
- bool IsAVLTree()
- {
- return _IsAVLTree(_root);
- }
- };