数据结构-红黑树

红黑树

与二分搜索树和AVL树的对比

  • 对于完全随机的数据,普通的二分搜索树很好用!
    缺点:极端情况退化成链表(或者高度不平衡)
    对于查询较多的使用情况,AVL树很好用!
    红黑树牺牲了平衡性(2logn的高度)
    红黑树统计性能更优(综合增删改查所有的操作)
    还有类似的SplayTree伸展树
    红黑树,本质上还是二分搜索树
  • 1.每个节点或者是红色的,或者是黑色的
  • 2.根节点是黑色的
  • 3.每一个叶子节点(最后的空节点)是黑色的
  • 4.如果一个节点是红色的,那么它的孩子节点都是黑色的
  • 5.从任意一个节点到叶子节点,经过的黑色节点是一样的
    在这里插入图片描述

2-3树

  • 满足二分搜索树的基本性质
  • 其本身不是二叉树
  • 节点可以存放一个元素或者两个元素
  • 节点有两个孩子或者三个孩子
    在这里插入图片描述

2-3树如何维持绝对的平衡

在这里插入图片描述

红黑树

红黑树和2-3树是等价的

  • 代码实现2-3树会比较复杂,因为既要操作2节点还要操作3节点,没有像之前统一操作节点方便,所以产生出红黑树。
    在这里插入图片描述
    黑结点表示2结点,红子节点+父黑节点表示3节点,所有的红色节点都是左倾斜的
    在这里插入图片描述
    将2-3树表示为红黑树
    在这里插入图片描述
    在这里插入图片描述

红黑树性质

  • 每个节点是红色或者黑色
  • 根节点是黑色的
  • 每一个叶子节点(最后的空节点)是黑色的
  • 如果一个节点是红色的,那么它的孩子节点都是黑色的
  • 从任意一个节点到叶子节点,经过的黑色节点是一样的
  • 红黑树是保持“黑平衡”的二叉树,严格意义讲不是平衡二叉树
    最大高度:2logn 时间复杂度O(logn)
    但是相对于AVL而言,插入元素和删除元素更加便捷

红黑树中添加新元素

  • 2-3树中添加一个新元素
    添加到2节点,形成3节点
    添加到3节点,暂时形成4节点,再拆解
    所以,新来的元素总要和当前叶子节点融合,所以永远新元素为红色
    但是根节点必须是黑色的。

情况1 插入比根节点小的元素

  • 先添加节点42
    在这里插入图片描述
  • 再添加节点37,此时没毛病
    在这里插入图片描述

情况2 插入比根节点大的元素

在这里插入图片描述
需要左旋转
在这里插入图片描述
左旋转
在这里插入图片描述

情况3 已有3节点时,插入比根节点大的元素

在这里插入图片描述

  • 将42的左右孩子变为黑节点,42变为红色,继续向上融合
    在这里插入图片描述

情况4 已有3节点时,插入最小元素

在这里插入图片描述
右旋转
在这里插入图片描述

情况5 已有3节点时,插入中等元素

在这里插入图片描述

代码实现红黑树的添加

private static final boolean RED=true;
private static final boolean BLACK=false;
private class Node{
	public K key;
	public V value;
	public Node left,right;
	public boolean color;
	public Node(K key,V value) {
		this.key=key;
		this.value=value;
		left=null;
		right=null;
		color=RED;// 新创建节点为红色
	}
@Override
public String toString() {
	return "("+key+","+value+")";
	}
}
private Node root;
private int size;
public RBTree() {
	root=null;
	size=0;
}
private boolean isRed(Node node){
	if(node==null){
		return BLACK;
	}
	return node.color;
}
// 左旋转
private Node leftRotate(Node node){
	Node x=node.right;
	node.right=x.left;
	x.left=node;
	x.color=node.color;
	node.color=RED;
	return x;
}
// 右旋转
private Node rightRotate(Node node){
	Node x=node.left;
	node.left=x.right;
	x.right=node;
	x.color=node.color;
	node.color=RED;
	return x;
}
// 颜色翻转
private void flipColors(Node node){
	node.color=RED;
	node.left.color=BLACK;
	node.right.color=BLACK;
}
@Override
public void add(K key, V value) {
	root=add(root,key,value);
	// 最终根节点为黑色节点
	root.color=BLACK;
}
private Node add(Node node, K key, V value) {
	if(node==null){
		size++;
	return new Node(key,value); // 默认插入红色节点
	}
	if(key.compareTo(node.key)<0){
		node.left=add(node.left,key,value);
	}else if(key.compareTo(node.key)>0){
		node.right=add(node.right,key,value);
	}else{
		node.value=value;
	}
	// 何时左旋转
	if(isRed(node.right)&&!isRed(node.left)){
		node=leftRotate(node);
	}
	// 何时右旋转
	if(isRed(node.left)&&isRed(node.left.left)){
		node=rightRotate(node);
	}
	// 何时颜色翻转
	if(isRed(node.left)&&isRed(node.right)){
		flipColors(node);
	}
	return node;
}

猜你喜欢

转载自blog.csdn.net/zhang_ye_ye/article/details/89603549