红黑树
作者:互联网
从2-3-4树到红黑树:
- 红黑树是对概念模型2-3-4树的一种实现,在二叉树的属性中加入一个颜色属性来表示2-3-4树中不同的节点。
- 2-3-4树中的2节点对应着红黑树中的黑色节点,而2-3-4树中的非2节点是以红节点+黑节点的方式存在,红节点的意义是与黑色父节点结合,表达着2-3-4树中的3,4节点。
- 2节点直接转化为黑色节点;3节点这里可以有两种表现形式,左倾红节点或者右倾红节点。而4节点被强制要求转化为一个黑父带着左右两个红色儿子。
红黑树其实就是对概念模型2-3树(或者2-3-4树)的一种实现
红黑规则:
- 节点不是红色就是黑色;
- 根节点是黑色;
- 红黑树的叶子节点并非传统的叶子节点,红黑树的叶子节点是null节点(空节点)且为黑色;
- 同一路径,不存在连续的红色节;
- 任意节点到叶子节点经过的黑色节点数目相同;
- 约束4和5,保证了红黑树的大致平衡:根到叶子的所有路径中,最长路径不会超过最短路径的2倍。
-
红黑树在最坏的情况下,查找复杂度也是O(log2N)。
左旋:
1 public void leftRotate(RedBlackTreeNode p) { 2 // 在当前节点不为null时,才进行左旋操作 3 if (p != null) { 4 // 先记录p的右儿子 5 RedBlackTreeNode rightChild = p.right; 6 7 // 1. 空出右儿子的左子树 8 p.right = rightChild.left; 9 // 左子树不为空,需要更新父节点 10 if (rightChild.left != null) { 11 rightChild.left.parent = p; 12 } 13 14 // 2. 空出节点p的父节点 15 rightChild.parent = p.parent; 16 // 父节点指向右儿子 17 if (p.parent == null) { // 右儿子成为新的根节点 18 this.root = rightChild; 19 } else if (p == p.parent.left) { // 右儿子成为父节点的左儿子 20 p.parent.left = rightChild; 21 } else { // 右儿子成为父节点的右儿子 22 p.parent.right = rightChild; 23 } 24 25 // 3. 右儿子和节点p成功会师,节点p成为左子树 26 rightChild.left = p; 27 p.parent = rightChild; 28 } 29 }
右旋:
1 public void rightRotate(RedBlackTreeNode p) { 2 if (p != null) { 3 // 记录p的左儿子 4 RedBlackTreeNode leftChild = p.left; 5 6 // 1. 空出左儿子的右子树 7 p.left = leftChild.right; 8 // 右子树不为空,需要更新父节点 9 if (leftChild.right != null) { 10 leftChild.right.parent = p; 11 } 12 13 // 2. 空出节点p的父节点 14 leftChild.parent = p.parent; 15 // 父节点指向左儿子 16 if (p.parent == null) { // 左儿子成为整棵树根节点 17 this.root = leftChild; 18 } else if (p.parent.left == p) { // 左儿子成为父节点左儿子 19 p.parent.left = leftChild; 20 } else { // 左儿子成为父节点的右儿子 21 p.parent.right = leftChild; 22 } 23 24 // 3. 顺利会师 25 leftChild.right = p; 26 p.parent = leftChild; 27 } 28 }
红黑树新增节点:
- 新插入的节点默认为红色,原因:插入黑色节点会影响黑色高度,对红黑树的影响更大;
- 新增节点x时,循环的依据: x != null && x != root && x.parent.color == RED,即节点非空、不是整棵树的根节点(保证存在父节点)且父节点为红色(违反红黑规则4,需要调整);
- 完成循环调整后,需要将整棵树的根节点设为黑色,以满足红黑规则1;同时,根节点设为黑色,不会影响从根节点开始的所有路径的黑色高度。
删除节点:
- 删除节点时,通过节点替换实现删除;
- 假设替换节点为x,需要在x替换被删节点后,从x开始进行调整;
- 调整操作,循环的依据:
x != root && x.color == BLACK
,即替换节点不能为整棵树的根节点,替换节点的颜色为黑色(改变了红黑高度); - 完成循环调整后,需要将x设为黑色,结束调整。
总结:
- AVL是高度平衡的,频繁的插入和删除会引起频繁的rebalance,严重影响效率;
- 红黑树其实是一种折中的做法,插入最多会引起两次旋转,删除最多会引起三次旋转;
- 红黑树查找、插入、删除的复杂度都是O(logN)的,性能稳定, STL中set、map的底层实现都是红黑树。
标签:rightChild,parent,leftChild,红黑树,节点,left 来源: https://www.cnblogs.com/siu-miner/p/16221542.html