目录
前面已经介绍过了二叉搜索树,使用二叉搜索树可以缩短查找数据的时间,但如果数据是有序的序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。
为了更好的调整结点,会定义为三叉链
- template<class K, class V>
- struct AVLTreeNode
- {
- pair
_kv; - AVLTreeNode
* _left; - AVLTreeNode
* _right; - AVLTreeNode
* _parent; -
- int _bf; // balance factor
-
- AVLTreeNode(const pair
& kv) - :_kv(kv)
- , _left(nullptr)
- , _right(nullptr)
- , _parent(nullptr)//指向该结点的父亲
- , _bf(0)
- {}
- };
分为两部分:
- bool Insert(const pair
& kv) - {
-
- if (_root == nullptr)
- {
- _root = new Node(kv);
- _root->_bf = 0;
- return true;
- }
-
- Node* parent = nullptr;
- Node* cur = _root;
- while (cur)
- {
- if (cur->_kv.first < kv.first)
- {
- parent = cur;
- cur = cur->_right;
- }
- else if (cur->_kv.first > kv.first)
- {
- parent = cur;
- cur = cur->_left;
- }
- else
- {
- return false;
- }
- }
- cur = new Node(kv);
- if (parent->_kv.first < kv.first)
- {
- parent->_right = cur;
- }
- else
- {
- parent->_left = cur;
- }
-
- cur->_parent = parent;//是三叉链,要把新插入结点的父亲链接上
- }
当把结点插入之后,平衡因子也要相继做出调整。
当插入一个新结点,该结点的平衡因子是0,若该节点是父亲结点的右子树,那么父亲结点的平衡因子要+1,若是左子树,则-1。(规定不是一定的)。
如果父亲结点的平衡因子发生变动, 1(父亲结点的平衡因子变为1或-1,说明以父亲结点为子树的高度发生了变化,平衡因子还需往上更新) 2(父亲结点的平衡因子变为0,说明以父亲结点为子树的高度未发生变化,无需再做任何调整) 3(父亲结点的平衡因子变为-2或2,说明以父亲结点为子树已不满足二叉搜索树的规则,要对结点进行旋转调整)
举例:此时这棵树满足规则

插入结点后:

代码实现:
- while (parent)
- {
- if (cur == parent->_right)该节点是父亲结点的右子树,父亲结点平衡因子+1
- {
- parent->_bf++;
- }
- else
- {
- parent->_bf--;
- }
- if (parent->_bf == 0) //父亲结点的平衡因子变为0,说明以父亲结点为子树的高度未发生
- 变化,无需再做任何调整
- {
- break;
- }
- else if (parent->_bf == 1 || parent->_bf == -1),平衡因子往上更新,最多更新到根
- {
- cur = cur->_parent;
- parent = parent->_parent;
- }
- }
二叉搜索树中插入新结点后,保证每个结点的左右子树高度之差的绝对值不超过1,如果某个结点的平衡=2或-2,就要对结点进行调整。
1.右单旋(处理LL型违规)

把parent->left=subLR;subL->right->parent;还要把parent,subL的平衡因子置为0。
代码实现:
- void RotateR(Node* parent)
- {
- Node* subL = parent->_left;
- Node* subLR = subL->_right;
-
- parent->_left = subLR;
- if (subLR)//subLR可能为空,例如上图第一种情况
- subLR->_parent = parent;
-
- Node* ppNode = parent->_parent;//先保留parent的父亲结点
-
- subL->_right = parent;
- parent->_parent = subL;
-
- if (parent == _root)//如果parent是根结点,则把subL置为根结点,并把它的parent置为空
- {
- _root = subL;
- _root->_parent = nullptr;
- }
- else
- {
- if (ppNode->_left == parent)//如果parent不是根节点,调整后,还需链接subL和ppNode
- 的关系
- {
- ppNode->_left = subL;
- }
- else
- {
- ppNode->_right = subL;
- }
- subL->_parent = ppNode;
- }
-
- subL->_bf = parent->_bf = 0;//把二者的平衡因子置为0;
- }
2. 左单旋(处理RR型违规)

与左单旋类似,把parent->right=subRL,subR->left=parent;也要调节它们的父亲关系
代码实现:
- void RotateL(Node* parent)
- {
- Node* pparent = parent->_parent;
- Node* subR = parent->_right;
- Node* subRL = subR->_left;
-
- parent->_right = subRL;
- subR->_left = parent;
- parent->_parent = subR;
- if (subRL)
- subRL->_parent = parent;
- if (parent == _root)
- {
- subR->_parent = nullptr;
- }
- else
- {
- if (parent == pparent->_left)
- pparent->_left = subR;
- else
- pparent->_right = subR;
-
- subR->_parent = pparent;
- }
- parent->_bf = 0;
- subR->_bf = 0;
- }
3.左右单旋
当parent的平衡因子=2,但subL的平衡因子=-1时。
先将subL为根节点的子树左旋,再将以parent为根的树右旋。
但与单旋不同,双旋后平衡因子会有多种组合结果。(以subLR的平衡因子进行判断)


代码实现:
- void RotateLR(Node* parent)
- {
- Node* subL = parent->_left;
- Node* subLR = subL->_right;
- int bf = subLR->_bf;
-
- RotateL(parent->_left);//先将subL为根节点的子树左旋
-
- RotateR(parent);//再将以parent为根的树右旋。
-
- if (bf == 0)
- {
- parent->_bf = 0;
- subL->_bf = 0;
- subLR->_bf = 0;
- }
- else if (bf == 1)
- {
- parent->_bf = -1;
- subL->_bf = 0;
- subLR->_bf = 0;
- }
- else if (bf == -1)
- {
- parent->_bf = 0;
- subL->_bf = 1;
- subLR->_bf = 0;
- }
- else
- {
- // subLR->_bf旋转前就有问题
- assert(false);
- }
- }
4.右左旋转
当parent的平衡因子=-2,但subR的平衡因子=1时。
先将subR为根节点的子树右旋,再将以parent为根的树左旋。
但与单旋不同,双旋后平衡因子会有多种组合结果。(以subRL的平衡因子进行判断)
代码实现:
- void RotateRL(Node* parent)
- {
- Node* subR = parent->_right;
- Node* subRL = subR->_left;
- int bf = subRL->_bf;
-
- RotateR(parent->_right);
- RotateL(parent);
-
- if (bf == 0)
- {
- subRL->_bf = 0;
- parent->_bf = 0;
- subR->_bf = 0;
- }
- else if (bf == -1)
- {
- subRL->_bf = 0;
- parent->_bf = 1;
- subR->_bf = 0;
- }
- else if (bf == 1)
- {
- subRL->_bf = 0;
- parent->_bf = 0;
- subR->_bf = -1;
- }
- else
- {
-
- assert(false);
- }
- }