Java中的TreeMap底层是由红黑树实现的
红黑树是具有下列着色性质的二叉树
- 每一个节点或者着红色,或者着黑色
- 根是黑色的
- 每个叶子都是黑色的空节点
- 每个红色节点的两个子节点都是黑色的
- 从一个节点到一个null引用的每一条路径必须包含相同数目的黑色节点
将新项作为树叶插入树中,该项必须为红色
- 如果其父节点是黑色,那么插入完成
- 如果其父节点是红色,那么需要进行颜色的改变和树的旋转
此时其祖父一定是黑色的
若是一字型的情形,那么将父与祖父进行单旋转,此时祖父-父-子的颜色分别为黑-红-黑
若是之字形的情形,那么进行双旋转:子与父进行单旋转,再与祖父进行单旋转,此时祖父-父-子的颜色分别为黑-红-黑
黑节点的孩子可以是黑节点或红节点,一旦有红节点之后,红节点所在的子树必然是红- 黑-红…交错的
class RedBlackTree<T extends Comparable<? super T>>
{
//设定颜色
public static final int BLACK = 1;
public static final int RED = 0;
//节点类
private static class RedBlackNode<T>
{
T element;
RedBlackNode<T> left;
RedBlackNode<T> right;
int color;
RedBlackNode(T element)
{
this(element, null, null);
}
RedBlackNode(T element, RedBlackNode<T> left, RedBlackNode<T> right)
{
this.element = element;
this.left = left;
this.right = right;
this.color = RedBlackTree.BLACK;
}
}
//声明头节点,其右子树是根
private RedBlackNode<T> header;
//声明一个空节点
private RedBlackNode<T> nullNode;
//初始化红黑树
public RedBlackTree()
{
nullNode = new RedBlackNode<>(null);
nullNode.left = nullNode.right = nullNode;
header = new RedBlackNode<>(null);
header.left = header.right = nullNode;
}
//判断树是否为空
public boolean isEmpty()
{
return header.right == nullNode;
}
//清空树
public void makeEmpty()
{
header.right = nullNode;
}
//插入方法的辅助节点
private RedBlackNode<T> current;
private RedBlackNode<T> parent;
private RedBlackNode<T> grand;
private RedBlackNode<T> great; //曾祖
//插入
public void insert(T t)
{
//初始化子、父、祖父
current = parent = grand = header;
//为空节点赋值,空节点应该在所有叶子位置上
nullNode.element = t;
//自顶向下找到current要插入的位置
while(compare(t, current) != 0)//找到空节点的时候相等
{
//向下一层
great = grand;
grand = parent;
parent = current;
//判断向下的方向(左、右)
if( compare(t, current) < 0)
current = current.left;
else
current = current.right;
//如果current的两个子树都是红色,那么重新处理
if(current.left.color == RED && current.right.color == RED)
handleReorient(t);
}
//不允许重复元素
if(current != nullNode)
return;
current = new RedBlackNode<>(t, nullNode, nullNode);//不是null,下面要用到它的子树
//与父节点相连
if(compare(t, parent) < 0)
parent.left = current;
else
parent.right = current;
handleReorient(t);
}
private void handleReorient(T t)
{
//颜色翻转,current变为红,子树变为黑
current.color = RED;
current.left.color = BLACK;
current.right.color = BLACK;
//当parent为黑,那么就颜色翻转后符合规则,继续向下
//当parent为红,current必须为黑,因此需要旋转
if(parent.color == RED)
{
//parent为红,grand一定为黑,需要变红
grand.color = RED;
if((compare(t, grand) < 0) != (compare(t, parent) < 0)) //之字形,两次旋转
parent = rotate(t, grand); //父与祖进行旋转
current = rotate(t, great); //一字型的旋转和之字形的双旋转第二次,当前与曾祖进行旋转
//current必须为黑
current.color = BLACK;
}
//根一定为黑色
header.right.color = BLACK;
}
//旋转方法
private RedBlackNode<T> rotate(T t, RedBlackNode<T> parent)
{
if(compare(t, parent) < 0)
return parent.left = (compare(t, parent.left) < 0)?
rotateWithLeftChild(parent.left): //t在parent.lef左下方,左一字型
rotateWithRightChild(parent.left);//t在parent.right右下方,之字形双旋转第一次
else
return parent.right =(compare(t, parent.right) < 0)?
rotateWithLeftChild(parent.right)://t在parent.right左下方,之字形双旋转第一次
rotateWithRightChild(parent.right);//t在parent.right右下方,右一字型
}
//左左单旋转
private RedBlackNode<T> rotateWithLeftChild(RedBlackNode<T> k2)
{
RedBlackNode<T> k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
return k1;
}
//右右单旋转
private RedBlackNode<T> rotateWithRightChild(RedBlackNode<T> k1)
{
RedBlackNode<T> k2 = k1.right;
k1.right = k2.left;
k2.left = k1;
return k2;
}
//比较方法,考虑p是头节点(元素为null),那么t永远大于头节点的元素
private int compare(T t, RedBlackNode<T> p)
{
if(p == header)
return 1;
return t.compareTo(p.element);
}
//最小值
public T findMin()
{
if(isEmpty())
throw new RuntimeException();
RedBlackNode<T> p = header.right;
while(p.left != nullNode)
p = p.left;
return p.element;
}
//最大值
public T findMax()
{
if(isEmpty())
throw new RuntimeException();
RedBlackNode<T> p = header.right;
while(p.right != nullNode)
p = p.right;
return p.element;
}
//包含
public boolean contains(T t)
{
if(isEmpty())
return false;
nullNode.element = t;
current = header.right;
while(true)
{
if(t.compareTo(current.element) < 0)
current = current.left;
else if(t.compareTo(current.element) > 0)
current = current.left;
else if(current != nullNode)
return true;
else
return false;
}
}
//中序遍历
public void midPrintTree()
{
if(isEmpty())
System.out.println("Empty Tree");
midPrintTree(header.right);
}
private void midPrintTree(RedBlackNode<T> p)
{
if(p != nullNode)
{
midPrintTree(p.left);
System.out.println(p.element +" "+ p.color);
midPrintTree(p.right);
}
}
}