1.概念
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。
因此,两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年发明了一种解决上述问题的方法:
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
左右子树高度之差(简称平衡因子)的绝对值不超过1(-1/0/1),如下图:
如果一棵二叉搜索树是高度平衡的,它就是AVL树。如果它有n个结点,其高度可保持在logn,搜索时间复杂度O(logN)
2.AVL树的插入
AVL树就是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看成是二叉搜索树。
平衡因子(_bf)就是该节点右子树高度减去左子树高度
那么 AVL树的插入过程可以分为两步:
1. 按照二叉搜索树的方式插入新节点
2. 调整节点的平衡因子
调整节点的平衡因子
一个合格的AVL树在插入之前,就应该满足AVL树的条件,插入节点的父亲节点的平衡因子只有三种可能(-1,0,1)
插入分以下几种情况:
第一种和第四种插入后子树的高度没有变化,所以上面的节点的平衡因子都不会变,平衡因子的更新可以结束了
第二种和第三种插入后子树的高度发生变化,所以上面的节点的平衡因子要变,要继续更新平衡因子
继续更新后如果有一个节点的平衡因子不再是(-1,0,1)也就是变成2或者-2,就要进行处理
平衡因子变成2或者-2的节点的子树,对于这个子树,一定是高的那个子树插入一个节点,导致在原先就高的那一边的子树,更加高了
我们可以分成以下几种情况继续分析
2 1树(左旋)
平衡因子不合格的本质是树的高度差太大,所以需要降高度。
对8左旋:
-2 -1树(右旋)
对8右旋:
-2 1树(左右旋)
先对8左旋再对10右旋:
这里加在b,也可以加在c,还有可能9就是新增节点,但是中间旋转的过程都是不变的,改变的只有平衡因子,但顶部的平衡因子一定为0。
2 -1 树(右左旋)
先对10右旋再对8左旋:
和上面一样,这里加在c,也可以加在b,还有可能9就是新增节点,但是中间旋转的过程都是不变的,改变的只有平衡因子,但顶部的平衡因子一定为0。
3.AVL树的删除
删除我熬了一个通宵搞明白的,不容易啊
3.1.删除节点
先考虑一下,删除有哪些情况:
1.删除的节点左右都为空,删除的就是叶子节点
2.删除的节点左右一边为空,只有以下两种情况,因为这是AVL树,所有节点的平衡因子只能是(-1,0,1)
现在已知一边为空,所以平衡因子=另一边子树的高度,所以只能有一个节点
3.删除的节点的左右都都不为空,这种情况,和搜索二叉树的找月嫂思想是一样的
这三种情况的解决方式有异曲同工之处
情况1:删除叶子节点,如果他是父亲的左孩子,(bf)平衡因子++,反之--
情况2:可以把被删除的节点存储的值和他的唯一的孩子交换,然后删除他的孩子,问题转换成情况1
情况3:找到左子树的最大值节点,与其交换一下存储的内容,问题转换成删除那个左子树最大的节点,这个节点,又符合左为空的情况,如果右也为空就是情况1,反之情况2
删除节点最后都会转为删除叶子节点
3.2.平衡因子更新
节点删除了,被删除节点的父亲节点的平衡因子也更新了,但是是否需要继续更新,当前位置是否平衡都需要考虑
平衡因子的正常范围是[-1,1]
被删除节点的父亲节点平衡因子可以分为以下三种情况:
1.bf == 0
说明原先该节点的bf == -1 或者 1 变成 0 后 说明原先高的那一边被删除了,导致高的子树高度降低,变得和另一边一样高,整颗树树的高度发生了变化,需要继续更新
2.bf == 1 或者 -1
说明原先该节点的bf == 0 0 变成 1 后 说明原先平衡,删除了一边,导致一边子树的高度变低了,但整颗树的高度没有变化,不需要更新
3. bf == 2 或者 bf == -2
这颗子树不平衡了,需要处理
3.3.旋转
不平衡分成两种大情况:
1.由于删除节点,导致当前子树不平衡
2.由于删除节点后导致平衡因子更新,而导致树不平衡
在更新平衡因子过程中,cur的bf一定是变成0,才会进一步,导致parent变化
在这个过程中,parent的bf变成2或者-2,是判断是否需要旋转的条件
而具体该怎么旋转,就由叔叔决定,因为cur的bf一定是0。和上面插入的旋转道理是一样的,也是这四种旋转。
这里右六种情况:
因为parent的bf可以是-2或者2,uncle的bf可以是-1,0,1
parent->bf | uncle->bf | 旋转方式 |
2 | 1 | 左旋 |
2 | 0 | 左旋 |
2 | -1 | 右左双旋 |
-2 | 1 | 右旋 |
-2 | 0 | 右旋 |
-2 | -1 | 左右双旋 |
在旋转之后还需要更新cur和parent,因为还有继续更新平衡因子的需要
4.源代码
#pragma once
#include<assert.h>template<class K, class V>
struct AVLtreeNode
{AVLtreeNode* _left;AVLtreeNode* _right;AVLtreeNode* _parent;pair<K, V> _kv;int _bf;AVLtreeNode(const K& key, const V& val):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(key, val),_bf(0){}
};template<class K, class V>
class AVLtree
{
public:typedef AVLtreeNode<K, V> Node;typedef pair<K, V> value_type;AVLtree() :_root(nullptr){}bool insert(const value_type& val){if (_root == nullptr){_root = new Node(val.first, val.second);return true;}// 找插入位置Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_kv.first > val.first)cur = cur->_left;else if (cur->_kv.first < val.first)cur = cur->_right;elsereturn false;}// 插入if (parent->_kv.first > val.first){parent->_left = new Node(val.first, val.second);cur = parent->_left;cur->_parent = parent;}else{parent->_right = new Node(val.first, val.second);cur = parent->_right;cur->_parent = parent;}// 更新_bf平衡因子while (parent){if (cur == parent->_left)parent->_bf--;elseparent->_bf++;if (parent->_bf == -1 || parent->_bf == 1){//继续更新cur = parent;parent = parent->_parent;}else if (parent->_bf == 0){//无需继续更新break;}else if (parent->_bf == -2 || parent->_bf == 2){//不平衡,要旋转if (parent->_bf > 0 && cur->_bf > 0)RotateL(parent);else if (parent->_bf < 0 && cur->_bf < 0)RotateR(parent);else if (parent->_bf > 0 && cur->_bf < 0)RotateRL(parent);elseRotateLR(parent);break;}else{assert(false);}}return true;}bool erase(const K& key){if (_root == nullptr){return false;}//找keyNode* cur = _root;while(cur){if (cur->_kv.first > key){cur = cur->_left;}else if (cur->_kv.first < key){cur = cur->_right;}else//找到了{if (cur->_left == nullptr && cur->_right == nullptr)//删除的节点是叶子节点{cur = DeleteNode(cur);}else if (cur->_left == nullptr){Node* del = cur->_right;cur->_kv = del->_kv;cur = DeleteNode(del);}else if (cur->_right == nullptr){Node* del = cur->_left;cur->_kv = del->_kv;cur = DeleteNode(del);}else{//找左子树的最大节点Node* leftmax = cur->_left;while (leftmax->_right)leftmax = leftmax->_right;cur->_kv = leftmax->_kv;//是否需要托孤if(leftmax->_left){Node* del = leftmax->_left;leftmax->_kv = del->_kv;cur = DeleteNode(del);}else{Node* del = leftmax;cur = DeleteNode(del);}}if (cur == nullptr)//根节点被删除return true;if (cur->_bf == 2 || cur->_bf == -2)//删除那个节点导致不平衡{Node* parent = cur;cur = nullptr;Rotate_delete_check(parent, cur);}//更新平衡因子Node* parent = cur->_parent;while (parent && cur->_bf == 0)//cur的平衡因子是0才需要更新{if (parent->_left == cur)parent->_bf++;elseparent->_bf--;if (parent->_bf == -1 || parent->_bf == 1){//无需继续更新break;}else if (parent->_bf == 0){//继续更新cur = parent;parent = parent->_parent;}else if (parent->_bf == -2 || parent->_bf == 2){cout << "//" << endl;Rotate_delete_check(parent, cur);}}return true;}}return false;}bool check_balance(){return _check_balance(_root);}void InOrder(){_InOrder(_root);cout << endl;}private:Node* DeleteNode(Node* cur)//删除叶子节点,并且返回其父亲{Node* del = cur;Node* parent = cur->_parent;if (parent == nullptr)//cur是根节点{_root = nullptr;delete del;return nullptr;}if (parent->_left == del){parent->_left = nullptr;parent->_bf++;}else{parent->_right = nullptr;parent->_bf--;}delete del;return parent;}void Rotate_delete_check(Node*& parent, Node*& cur){Node* uncle;if (parent->_left == cur)uncle = parent->_right;elseuncle = parent->_left;if (parent->_bf == 2 && uncle->_bf == 1){RotateL(parent);cur = uncle;}else if (parent->_bf == -2 && uncle->_bf == -1){RotateR(parent);cur = uncle;}else if (parent->_bf == 2 && uncle->_bf == -1){cur = uncle->_left;RotateRL(parent);}else if (parent->_bf == -2 && uncle->_bf == 1){cur = uncle->_right;RotateLR(parent);}else if (parent->_bf == 2 && uncle->_bf == 0){RotateL(parent);parent->_bf = 1;uncle->_bf = -1;cur = uncle;}else if (parent->_bf == -2 && uncle->_bf == 0){RotateR(parent);parent->_bf = -1;uncle->_bf = 1;cur = uncle;}else assert(false);parent = cur->_parent;}void balence_check(Node* parent, Node* cur){if (parent == nullptr)return;if (parent->_bf == 0){//无需继续更新}else if (parent->_bf == -2 || parent->_bf == 2){//不平衡,要旋转if (parent->_bf > 0 && cur->_bf > 0)RotateL(parent);else if (parent->_bf < 0 && cur->_bf < 0)RotateR(parent);else if (parent->_bf > 0 && cur->_bf < 0)RotateRL(parent);elseRotateLR(parent);}}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);}bool _check_balance(Node* root){if (root == nullptr)return true;int lefthight = TreeHight(root->_left);int righthight = TreeHight(root->_right);if (abs(lefthight - righthight) >= 2 || righthight - lefthight != root->_bf){cout << root->_kv.first << ":" << root->_bf << endl;return false;}return _check_balance(root->_left) && _check_balance(root->_right);}int TreeHight(Node* root){if (root == nullptr)return 0;int lefthight = TreeHight(root->_left);int righthight = TreeHight(root->_right);return lefthight > righthight ? lefthight + 1: righthight + 1;}void RotateL(Node* parent)//左单旋{Node* Rightson = parent->_right;//旋转节点之间的链接parent->_right = Rightson->_left;if (parent->_right)parent->_right->_parent = parent;Rightson->_left = parent;Node* pparent = parent->_parent;parent->_parent = Rightson;//更新祖先的链接if (pparent == nullptr){Rightson->_parent = nullptr;_root = Rightson;}else{if (pparent->_kv.first > Rightson->_kv.first)pparent->_left = Rightson;elsepparent->_right = Rightson;Rightson->_parent = pparent;}parent->_bf = Rightson->_bf = 0;}void RotateR(Node* parent)//右单旋{Node* Leftson = parent->_left;//旋转节点之间的链接parent->_left = Leftson->_right;if (parent->_left)parent->_left->_parent = parent;Leftson->_right = parent;Node* pparent = parent->_parent;parent->_parent = Leftson;//更新祖先的链接if (pparent == nullptr){Leftson->_parent = nullptr;_root = Leftson;}else{if (pparent->_kv.first > Leftson->_kv.first)pparent->_left = Leftson;elsepparent->_right = Leftson;Leftson->_parent = pparent;}parent->_bf = Leftson->_bf = 0;}void RotateLR(Node* parent){Node* Leftson = parent->_left;Node* LRightsson = Leftson->_right;int bf = LRightsson->_bf;RotateL(Leftson);RotateR(parent);//平衡因子更新if (bf == 1){Leftson->_bf = -1;}else if (bf == -1){parent->_bf = 1;}else if (bf == 0) {}else{assert(false);}}void RotateRL(Node* parent){Node* Rightson = parent->_right;Node* RLeftsson = Rightson->_left;int bf = RLeftsson->_bf;RotateR(Rightson);RotateL(parent);//平衡因子更新if (bf == 1){parent->_bf = -1;}else if (bf == -1){Rightson->_bf = 1;}else if(bf == 0){}else{assert(false);}}private:Node* _root;
};
写完了。