红黑树(RBTree)知识总结
概念
红黑树是一种二叉搜索树,但在每个节点上增加一个模拟存储位表示节点的颜色(红|黑),可以通过任何一条从根到叶子路径上各个着色方式的限制确保没有一条路径会比其他路径长出两倍,因而接近平衡
性质
1.每个节点不是红色就是黑色
2.根节点是黑色的
3.如果有一个节点是红色的,则他的两个孩子节点是黑色的(没有两个连续的红色节点)
4.对于每个节点,从该节点到其所有后代叶节点的简单路径上均包含着相同数目的黑色节点
5.每个叶子结点都是黑色的(这里的叶子结点指的是空节点)
为什么能保证最长路径中结点个数不会超过最短路径节点的个数的2倍?
最短路径:全为黑色 最长路径:每两个黑的之间是红的
假设一个红黑树有x个黑色的结点,N为总结点
N的范围为【N,2N】
时间复杂度:logN,相对平衡的
模拟实现红黑树的插入
模拟实现
定义
颜色(枚举),左孩子,右孩子,父亲节点,值
这里注意新增的结点默认是红色的(如果是黑色的,那么要保证每条路径上黑色节点是相等的,那么就又要新增黑色节点,更加复杂)
public enum COLOR {RED,BLACK
}static class RBTreeNode {public RBTreeNode left ;public RBTreeNode right;public RBTreeNode parent;public int val;public COLOR color;public RBTreeNode(int val) {this.val = val;//我们新创建的节点,颜色默认是红色的.为什么?this.color = COLOR.RED;}}public RBTreeNode root;
public boolean insert(int val) {RBTreeNode node = new RBTreeNode(val);if (root == null) {root = node;root.color = COLOR.BLACK;return true;}RBTreeNode parent = null;RBTreeNode cur = root;while (cur != null) {if (cur.val < val) {parent = cur;cur = cur.right;} else if (cur.val == val) {return false;} else {parent = cur;cur = cur.left;}}//cur == nullif (parent.val < val) {parent.right = node;} else {parent.left = node;}//node.parent = parent;cur = node;//红黑树来说:就需要调整颜色while (parent != null && parent.color == COLOR.RED) {RBTreeNode grandFather = parent.parent;//这个引用不可能为空if(parent == grandFather.left) {RBTreeNode uncle = grandFather.right;if(uncle != null && uncle.color == COLOR.RED) {parent.color = COLOR.BLACK;uncle.color = COLOR.BLACK;grandFather.color = COLOR.RED;//继续向上修改cur = grandFather;parent = cur.parent;}else {//uncle不存在 或者 uncle是黑色的//情况三:if(cur == parent.right) {rotateLeft(parent);RBTreeNode tmp = parent;parent = cur;cur = tmp;}//情况三 变成了情况二//情况二rotateRight(grandFather);grandFather.color = COLOR.RED;parent.color = COLOR.BLACK;}}else {//parent == grandFather.rightRBTreeNode uncle = grandFather.left;if(uncle != null && uncle.color == COLOR.RED) {parent.color = COLOR.BLACK;uncle.color = COLOR.BLACK;grandFather.color = COLOR.RED;//继续向上修改cur = grandFather;parent = cur.parent;}else {//uncle不存在 或者 uncle是黑色的//情况三:if(cur == parent.left) {rotateRight(parent);RBTreeNode tmp = parent;parent = cur;cur = tmp;}//情况三 变成了情况二//情况二rotateLeft(grandFather);grandFather.color = COLOR.RED;parent.color = COLOR.BLACK;}}}root.color = COLOR.BLACK;return true;}
旋转的代码详见avlTree
红黑树的验证
红黑树验证本质就是要满足红黑树的性质
1.根是黑的
2.没有两个连续的红色节点(往回看,遇到红看p是否为黑)
3.每条路上有相同黑色节点的数量
public boolean isRBTree() {if(root == null) {//如果一棵树是空树,那么这棵树就是红黑树return true;}if(root.color != COLOR.BLACK) {System.out.println("违反了性质:根节点必须是黑色的!");}//存储当前红黑树当中 最左边路径的黑色的节点个数int blackNum = 0;RBTreeNode cur = root;while (cur != null) {if(cur.color == COLOR.BLACK) {blackNum++;}cur = cur.left;}//检查是否存在两个连续的红色节点 && 每条路径上黑色的节点的个数是一致的return checkRedColor(root) && checkBlackNum(root,0,blackNum);}private boolean checkBlackNum(RBTreeNode root,int pathBlackNum,int blackNum) {if(root == null) return true;if(root.color == COLOR.BLACK) {pathBlackNum++;}if(root.left == null && root.right == null) {if(pathBlackNum != blackNum) {System.out.println("违反了性质:每条路径上黑色的节点个数是不一样的!");return false;}}return checkBlackNum(root.left,pathBlackNum,blackNum) &&checkBlackNum(root.right,pathBlackNum,blackNum);}private boolean checkRedColor(RBTreeNode root) {if(root == null) return true;if(root.color == COLOR.RED) {RBTreeNode parent = root.parent;if(parent.color == COLOR.RED) {System.out.println("违反了性质:连续出现了两个红色的节点");return false;}}return checkRedColor(root.left) && checkRedColor(root.right);}public void inorder(RBTreeNode root) {if(root == null) {return;}inorder(root.left);System.out.print(root.val+" ");inorder(root.right);}
AVL树和红黑树比较
红黑树不追求绝对平衡,相对降低了插入和旋转的次数
AVL树追求绝对的平衡
红黑树的应用
1.TreeSet和TreeMap底层使用的是红黑树
2.C++STL库——map/set
3.linux内核