AVL树
- 左右子树都是AVL树
- 左右子树高度差的绝对值不超过1(-1/0/1)(一般:右子树高度 - 左子树高度)
- 如果一棵二叉搜索树树高度平衡的,它就是AVL树。如果它有n个节点,其高度可保持在O(log2N),搜索时间复杂度O(log2N)
节点结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| template <class T> struct AVLNode { T _value; int _bf; AVLNode<T>* _left; AVLNode<T>* _right; AVLNode<T>* _parent;
AVLNode(const T& val = T()) : _value(val) , _bf(0) , _left(nullptr) , _right(nullptr) , _parent(nullptr) { } };
|
插入节点后:必须要更新平衡因子
可能需要更新平衡因子的节点:
- 新插入节点中所有足祖先节点
- 如果节点的子树高度发生变化,则需要更新
插入
二叉搜索树的插入
从新插入的节点对应的父节点位置开始更新平衡因子
在第二步的过程中,平衡因子更新之后:
平衡因子:0 —-> 停止更新
平衡因子:-1/1 —-> 继续向上更新
平衡因子:-2/2 —-> 旋转
单旋:
左单旋:右边的右边高,parent->_bf == 2 && cur->_bf == 1
修改链接:parent、subRL、subR
parent->_right : subRL、subR->left : parent
更新平衡因子:parent、subR:0
右单旋:左边的左边高,parent->_bf == -2 && cur->_bf == -1
修改链接:subL、subLR、parent
parent->left : subLR、subL->right : parent
更新平衡因子:parent、subL:0
双旋:
左右双旋:左边的右边高,parent->_bf == -2 && cur->_bf == 1
修改链接:subL、subLR、parent
左旋:以subL为轴
右旋:以parent为轴
重新更新平衡因子:
if(subLR->bf == -1)
subL->bf = 0, parent->bf = 1;
else if(subLR->bf == 1)
subL->bf = -1, parent->bf = 0;
右左双旋右边的左边高,parent->_bf == 2 && cur->_bf == -1
修改链接:parent、subRL、subR
右旋:以subR为轴
左旋:以parent为轴
重新更新平衡因子:
if(subRL->bf == 1)
parent->bf = -1, subR->bf = 0;
else if(subRL->bf == -1)
parent->bf = 0, subR->bf = 1;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| bool insert(const T& val) { if (_root == nullptr) { _root = new Node(val); return true; } Node* cur = _root; Node* parent = nullptr; while (cur) { parent = cur; if (cur->_value == val) { return false; } else if (cur->_value < val) { cur = cur->_right; } else { cur = cur->_left; } }
cur = new Node(val); if (parent->_value < val) { parent->_right = cur; }else { parent->_left = cur; }
cur->_parent = parent;
while (parent) { if (parent->_left == cur) parent->_bf--; else parent->_bf++; if (parent->_bf == 0) { break; }else if (parent->_bf == -1 || parent->_bf == 1) { cur = parent; parent = parent->_parent; }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) { Node* subR = parent->_right; Node* subRl = subR->_left; int bf = subRL->_bf; RotateR(cur); RotateL(parent); if(bf == 1) { subR->_bf = 0; parent->_bf = -1; } else if(bf == -1) { parent->_bf = 0; subR->_bf = 1; } } else if (parent->_bf == -2 && cur->_bf == 1) { RotateL(cur); RotateR(parent); }
break; } } return true; }
|
左旋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| void RotateL(Node* parent) { Node* subR = parent->_right; Node* subRL = subR->_left;
subR->_left = parent; parent->_right = subRL;
if (subRL) subRL->_parent = parent;
if (parent == _root) { _root = subR; subR->_parent = nullptr; } else { Node* g = parent->_parent; subR->_parent = g; if (g->_left == parent) g->_left = subR; else g->_right = subR; }
parent->_parent = subR; parent->_bf = subR->_bf = 0; }
|
右旋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| void RotateR(Node* parent) { Node* subL = parent->_left; Node* subLR = subL->_right;
subL->_right = parent; parent->_left = subLR;
if (subLR) subLR->_parent = parent;
if (parent == _root) { _root = subL; subL->_parent = nullptr; } else { Node* g = parent->_parent; subL->_parent = g; if (g->_left == parent) g->_left = subL; else g->_right = subL; } parent->_parent = subL; parent->_bf = subL->_bf = 0; }
|
红黑树
- 每个节点不是红色就是黑色
- 根结点是黑色的
- 如果一个节点是红色的,则它的两个孩子节点是黑色的
- 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点
- 每个叶子节点都是黑色的(空节点也可)
根是黑色的
红色不能连续,黑色可以连续
每条路径上,黑色节点个数相同
最长路径是最短路径的两倍(最短:全黑;最长:红黑相间)
一个红黑树的简单实现 - GitHub
节点结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| enum Color { BLACK, RED };
template <class K, class V> struct RBNode { pair<K, V> _value; Color _color; RBNode<K, V> _parent; RBNode<K, V> _left; RBNode<K, V> _right;
RBNode(const pair<K, V>& value = pair<K, V>()) : _value(value) , _color(RED) , _parent(nullptr) , _left(nullptr) , _right(nullptr) { } };
|
插入
不能改变当前结构中的黑色节点的个数,除了祖父节点为根节点的情况
- 搜索树的插入
- 判断是否需要调整:红色连续
- cur在p左边,叔叔存在且为红色,将p、u置为黑色,g为红色
- cur在p左边,叔叔不存在,以g为轴心进行右旋,将g变红,将p变黑
- cur在p左边叔叔为黑色,以g为轴心进行右旋,将g变红,将p变黑
- cur在p右边,先以p为轴心左旋,交换p与cur指针,按照情况三处理
代码如下,其中旋转部分代码与AVL树相同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| bool insert(const pair<K, V>& val) { if (_header->_parent == nullptr) { Node* root = new Node(val); root->_color = BLACK;
_header->_parent = root; root->_parent = _header;
_header->_left = root; _header->_right = root;
return true; } Node* cur = _header->_parent; Node* parent = nullptr; while (cur) { parent = cur; if (cur->_value.first == val.first) return false; if (cur->_value.first < val.first) cur = cur->_right; else cur = cur->_left; }
cur = new Node(val); if (parent->_value.first < val.first) parent->_right = cur; else parent->_left = cur;
cur->_parent = parent;
while (cur != _header->_parent && cur->_parent->_color == RED) { Node* p = cur->_parent; Node* g = p->_parent; if (g->_left == p) { Node* u = g->_right; if (u && u->_color == RED) { u->_color = p->_color = BLACK; g->_color = RED;
cur = g; } else { if (cur == p->_right) { RotateL(p); swap(cur, p); }
RotateR(g); p->_color = BLACK; g->_color = RED;
break; } } else { Node* u = g->_left; if (u && u->_color == RED) { u->_color = p->_color = BLACK; g->_color = RED; cur = g; } else { if (cur == p->_left) { RotateR(p); swap(cur, p); }
RotateL(g); g->_color = RED; p->_color = BLACK;
break; } } } _header->_parent->_color = BLACK; _header->_left = leftMost(); _header->_right = rightMost();
return true; }
|