红黑树底层实现原理分析及JAVA代码实现
Posted 求思之路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了红黑树底层实现原理分析及JAVA代码实现相关的知识,希望对你有一定的参考价值。
------------ 本文来自 [阿P官方博客](https://www.wxqsearch.cn/article/72)
------------ 在线测试红黑树:[红黑树在线测试](https://www.wxqsearch.cn/demo/rbtree)
###一、红黑树
```markdown
自平衡二叉查找树(Binary Search Tree)
二叉查找树:
基于二叉树
左子树小于根,右子树大于根
缺点:如果选错根节点,整个树就不再平衡
特点
所有节点非红即黑
根节点一定是黑色
红节点的子节点一定是黑色
最低层的叶子节点一定是黑色
从根节点到任意叶子节点经历过的黑色节点一定相同
新增的节点颜色一定是红色节点
红黑树时间复杂度:O(logN) 与二分查找法一致
第一次查找数量 n/2
第二次查找数量 n/2/2
第三次查找数量 n/2/2/2
…...
第m次查找数量 n/(2^m)
由此我们可以得知时间复杂度=logN
```
###二、红黑树修正(遵循以下步骤进行修正)
```markdown
当前节点为红,父节点为红,并且叔父节点为红或为空
父节点、叔父节点涂黑,祖父节点涂红。对祖父节点继续操作
当前节点为红且是右子叶,父节点为红,并且叔父节点为黑
以当前节点为轴,进行左旋
当前节点为红且是左子叶,父节点为红,并且叔父节点为黑
父节点涂黑,祖父节点涂红,以父节点为轴,进行右旋
```
###三、红黑树JAVA实现类
```java
package RBTree;
/**
* 红黑树
*
*/
public class RBTreeDemo<T extends Comparable<T>> {
Node root;//根节点
Node min;//最左节点
Node max;//最右节点
Boolean RED = true;
Boolean BLACK = false;
/**
* 新增
* @param val
*/
public void add(T val)
{
if (this.root == null) {
//根节点为黑色
this.root = new Node<T>(val, this.BLACK, null, null, null);
return;
}
Node node = this.root;
//当前节点
Node current = new Node<T>(val, this.RED, null, null, null);
//遍历树,进行插入
while (true) {
if (val.compareTo((T) node.val) > 0) {//放右子节点
if (node.right == null) {
node.right = current;
current.parent = node;
break;
}
node=node.right;
} else {//放左子节点
if (node.left == null) {
node.left = current;
current.parent = node;
break;
}
node=node.left;
}
}
//插入完进行自平衡
fixUp(current);
}
/**
* 自平衡
*/
public void fixUp(Node node)
{
//当前节点没父节点,则涂黑
if (node.parent == null) {
node.color = this.BLACK;
this.root = node;
return;
}
//当前节点没有祖父节点
if (node.parent.parent == null) {
return;
}
//叔父节点 可以为空
Node uncleNode = this.getUncleNode(node);
//当前节点为红,且父节点为红
if (node.color == this.RED && node.parent.color == this.RED) {
//叔父节点为空或者为红,就进行涂色
if (uncleNode == null || uncleNode.color == this.RED) {
node.parent.color = this.BLACK;
if (uncleNode != null) {
uncleNode.color=this.BLACK;
}
node.parent.parent.color = this.RED;
this.fixUp(node.parent.parent);
} else if (uncleNode.color == this.BLACK) {
//自己是左子叶
if (node.parent.left.equals(node)) {
this.right(node);
this.fixUp(node.parent);//右旋后,修改当前节点颜色
} else {//自己是右子叶
this.left(node);
this.fixUp(node.left);//曾经的父节点
}
}
}
}
/**
* 叔父节点,可以为空
* @param node
* @return
*/
private Node getUncleNode(Node node) {
Node uncleNode= node.parent.parent.left;
if (uncleNode == null || node.parent.equals(uncleNode)) {
uncleNode = node.parent.parent.right;
}
return uncleNode;
}
/**
* 当前结点为红,且处于右子叶上。父节点为红,叔父节点为黑或空时。以当前节点为轴进行左旋
* 当前节点的祖父节点,变成自己的父节点
* 当前节点的父节点,变成自己的左节点
* 当前节点的左节点,变成当前右节点的右节点
*/
private void left(Node node) {
Node parent = node.parent;
Node left = node.left;
Node pParent = node.parent.parent;
//祖父节点
pParent.left = node;
//父节点
parent.parent = node;
parent.right = left;
//左节点
left.parent = parent;
//当前节点
node.parent = pParent;
node.left = parent;
}
/**
* 当前结点为红,且处于左子叶上。父节点为红,叔父节点为黑时。以父节点为轴进行右旋
*/
private void right(Node node) {
Node parent = node.parent;
Node right = parent.right;
Node pParent = node.parent.parent;
Node ppParent = node.parent.parent.parent;
//涂色
pParent.color = this.RED;
parent.color = this.BLACK;
if (ppParent != null) {
//祖祖父节点
if (ppParent.right.equals(pParent)) {
ppParent.right = parent;
} else {
ppParent.left = parent;
}
}
//祖父节点
pParent.left = right;
pParent.parent=parent;
//父节点
parent.right = pParent;
parent.parent = ppParent;
//右子节点
right.parent = pParent;
}
/**
* 前序遍历 从根开始遍历
*/
private String preOrder(Node node) {
if (node == null) {
return null;//如果左侧树遍历完成,返回null
}
String strLeft = this.preOrder(node.left);
if (strLeft == null) {
strLeft="";
}
String strRight = this.preOrder(node.right);
if (strRight == null) {
strRight="";
}
return strLeft + node.toString() + strRight;
}
public String toString() {
//前序遍历
return preOrder(this.root);
}
/**
* 结点类
*/
private class Node<T>{
public T val;
public Boolean color;//红为true
public Node left;
public Node right;
public Node parent;
public Node(T val, Boolean color, Node left, Node right, Node parent) {
super();
this.val = val;
this.color = color;
this.left = left;
this.right = right;
this.parent = parent;
}
public String toString() {
String left = "-";
String right = "-";
if (this.left != null) {
left = this.left.val.toString();
}
if (this.right != null) {
right = this.right.val.toString();
}
return "[" + left + ", "+this.val.toString() + ", " + right +", "+ getColorName(this.color) + "]";
}
private String getColorName(Boolean color) {
return color == true? "红" : "黑";
}
public boolean equals(Object obj) {
Node obj1 = (Node)obj;
return obj1.val == this.val;
}
}
}
```
以上是关于红黑树底层实现原理分析及JAVA代码实现的主要内容,如果未能解决你的问题,请参考以下文章
ConcurrentHashMap底层实现原理(JDK1.8)源码分析