数据结构与算法之红黑树

(一) 2-3 树

2-3树: 是最简单的B-树(或-树)结构, 其每个非叶节点都有两个或三个子节点, 而且一个节点可以包含2个元素.

  • 2-3树虽然不是二叉树, 但满足二分搜索树的基本性质.
  • 2-3树是一棵绝对平衡的树: 对于任意一个节点, 左右子树的高度是相等的

2-3树的节点可以分为两种:

  • 2-节点: 和不同二分搜索树节点一样, 存储一个元素, 有左右两个孩子且左孩子节点元素小于该节点, 右孩子节点元素大于该节点.
  • 3-节点: 存储二个元素, 且有左中右三个子孩子. 左孩子节点元素小于该节点存储的第一个元素, 中孩子节点元素在该节点存储的二个元素之间, 右孩子节点元素大于该节点存储的的第二个元素.

在这里插入图片描述
2-3树的添加操作
添加操作一定会维持绝对平衡 且 添加的元素不会像二分搜索树添加到NULL节点的位置, 它一定是添加到匹配的叶子节点进行融合

图解: 向空的2-3添加元素 42,37,12,18,6,11,5
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(二) 红黑树(RedBlackTree)

红黑树和2-3树是等价的, 可以通过红黑树来描述2-3树: 红色节点代表当前节点和其父节点是2-3树中的3-节点且所有的红色节点都是向左倾斜
在这里插入图片描述
在这里插入图片描述

1.红黑树是满足以下红黑属性的二叉树:

结合上图理解

  • 每个节点要么是红色,要么是黑色
  • 根节点是黑色: 在2-3树中根节点要么是2-节点, 要么是3-节点
  • 每个叶子节点(最后的空节点)是黑色
  • 如果一个节点是红色的,那么他的孩子节点都是黑色的
  • 从任意一个节点到叶子节点,经过的黑色节点是一样的

2-3树是一颗绝对平衡的树, 任意节点到叶子节点所进过的节点数是一样的. 2-3树转换为红黑树时, 将3-节点转换为一红一黑的两个节点, 并且红色节点都是向左倾斜, 所以在经历3-节点时一定会先经历黑色节点. 红黑树是保持 “黑平衡” 的二叉树. 严格意义上, 红黑树不是平衡二叉树, 树最大高度为 2logn(每个黑色节点都有一个红色节点)

2.左倾红黑树基础结构
public class RedBlackTree<K extends Comparable<K>, V> {

	// 定义常量 RED, BLACK
	private static final boolean RED = true;
	private static final boolean BLACK = false;

	private class Node {
		
		public K key;
		public V value;
		public Node left;
		public Node right;
		
		/**
		 * 节点的颜色
		 */
		public boolean color;
		
		public Node(K key, V value) {
			this.key = key;
			this.value = value;
			this.left = null;
			this.right = null;
			
			// 默认初始化颜色为红色: 在2-3树中添加元素时一定是先与叶子节点融合, 而RED代表当前节点和其父节点是2-3树中的3节点
			color = RED;
		}
	}
	
	private Node root;
	private int size;
	
	public RedBlackTree() {
		this.root = null;
		this.size = 0;
	}
	
	public int getSize() {
		return this.size;
	}

	public boolean isEmpty() {
		return this.size == 0;
	}
	
	private Node getNode(Node node, K key) {
		if (node == null) {
			return null;
		} 
		if (node.key.compareTo(key) == 0) {
			return node;
		} else if (node.key.compareTo(key) < 0) {
			return getNode(node.right, key);
		} else {
			return getNode(node.left, key);
		}
	}
	
	/**
	 * 判断节点node的颜色, node为null返回BALCK (RED代表当前节点和其父节点是2-3树中的3节点)
	 * 
	 * @param node
	 * @return
	 */
	private boolean isRed(Node node) {
		if (node == null) {
			return BLACK;
		}
		return node.color;
	}
}
3.红黑树添加操作

2-3树中添加一个新元素, 要么添加进2-节点, 形成一个3-节点, 要么添加精3- 节点, 暂时形成一个4- 节点. 所以红黑树添加的新节点一定是红色的.

  • 红黑树添加操作的第一种情况: 添加的新元素(红色)在根节点(黑色)的右侧, 左旋转 node节点 与 x节点融合成 3-节点
    在这里插入图片描述
private Node leftRotate(Node node) {
	Node x = node.right;
	
	// 左旋转
	node.right = x.left;
	x.left = node;
	
	// 维护节点颜色, 有可能得到的x节点和node节点都为红色
	x.color = node.color;
	// node节点一定为红色, node节点 + x节点 组成 3-节点
	node.color = RED;
	
	return x;
}
  • 红黑树添加操作的第二种情况: 添加的新元素(红色)在3-节点的右侧, 颜色翻转flipColors
    在这里插入图片描述
private void flipColors(Node node) {
	node.color = RED;
	node.left.color = BLACK;
	node.right.color = BLACK;
}
  • 红黑树添加操作的第三种情况: 添加的新元素(红色)在3-节点的左侧, 右旋转 node节点 与 x节点融合成 3-节点
    在这里插入图片描述
private Node rightRotate(Node node) {
	Node x = node.left;
	
	// 右旋转
	node.left = x.right;
	x.right = node;
	
	// 维护节点颜色
	x.color = node.color;
	// node节点一定为红色, node节点 + x节点 组成 3-节点
	node.color = RED;
	
	return x;
}
  • 红黑树添加操作的第四, 五种情况
    在这里插入图片描述
public void add(K key, V value) {
	this.root = add(this.root, key, value);
	
	// 保持根节点是黑色节点
	root.color = BLACK;
}

/**
 * 向以node为根的红黑树中插入键值对key-value, 返回插入新节点后红黑树的跟
 * 
 * @param node
 * @param key
 * @param value
 * @return
 */
private Node add(Node node, K key, V value) {
	if (node == null) {
		size++;
		return new Node(key, value);
	}
	// 二分搜索树中存在插入key, 修改key对应的value
	if (node.key.compareTo(key) == 0) {
		node.value = value;
	} else if (node.key.compareTo(key) < 0) {
		node.right = add(node.right, key, value); 
	} else if (node.key.compareTo(key) > 0) {
		node.left = add(node.left, key, 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.right) && isRed(node.left)) {
		// 颜色翻转
		flipColors(node);
	}
	
	return node;
}

java.util中的TreeMap和TreeSet基于红黑树

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值