数据结构与算法(java版)第一季 - 11 红黑树(添加 删除代码没有写)

发布于:2022-08-06 ⋅ 阅读:(223) ⋅ 点赞:(0)

目录

错误示范

红黑树的等价变换

红黑树VS2-3-4树

几个英语单词​编辑

辅助函数

添加

 添加的所有情况

添加 - 修复性质4 - LL\RR

添加 – 修复性质4 – LR\RL

 添加 – 修复性质4 – 上溢 – LL

 添加 – 修复性质4 – 上溢 – LL​编辑

添加 – 修复性质4 – 上溢 – LR

添加 – 修复性质4 – 上溢 – RL​编辑 


错误示范

上述之中是存在null节点的,比如说上面的38的右边就是一个null,25 74 78 86 90下面的就是两个null,进而得知上面的叶子节点的不同之处,一定要注意null的存在.

所以上面的那个不是红黑树,注意空节点(null)的存在,一定要注意假的博客,有些标题很牛逼,但是可能就是错误的.

红黑树的等价变换

红黑树 和 4阶B树(2-3-4树)具有等价性
BLACK 节点与它的 RED 子节点融合在一起,形成1个B树节点
红黑树的 BLACK 节点个数 与 4阶B树的节点总个数 相等
网上有些教程:用2-3树与红黑树进行类比,这是极其不严谨的,2-3树并不能完美匹配红黑树的所有情况
注意:因为PPT界面空间有限,后面展示的红黑树都会省略 NULL 节点

红黑树VS2-3-4树

思考:如果上图最底层的 BLACK 节点是不存在的,在B树中是什么样的情形?
  整棵B树只有1个节点,而且是超级节点

几个英语单词

辅助函数

package com.mj.tree;

import java.util.Comparator;

public class RBTree<E> extends BBST<E> {
	private static final boolean RED = false;
	private static final boolean BLACK = true;
	
	public RBTree() {
		this(null);
	}
	
	public RBTree(Comparator<E> comparator) {
		super(comparator);
	}
	
	@Override
	protected void afterAdd(Node<E> node) {
		Node<E> parent = node.parent;
		
		// 添加的是根节点 或者 上溢到达了根节点
		if (parent == null) {
			black(node);
			return;
		}
		
		// 如果父节点是黑色,直接返回
		if (isBlack(parent)) return;
		
		// 叔父节点
		Node<E> uncle = parent.sibling();
		// 祖父节点
		Node<E> grand = red(parent.parent);
		if (isRed(uncle)) { // 叔父节点是红色【B树节点上溢】
			black(parent);
			black(uncle);
			// 把祖父节点当做是新添加的节点
			afterAdd(grand);
			return;
		}
		
		// 叔父节点不是红色
		if (parent.isLeftChild()) { // L
			if (node.isLeftChild()) { // LL
				black(parent);
			} else { // LR
				black(node);
				rotateLeft(parent);
			}
			rotateRight(grand);
		} else { // R
			if (node.isLeftChild()) { // RL
				black(node);
				rotateRight(parent);
			} else { // RR
				black(parent);
			}
			rotateLeft(grand);
		}
	}
	
	@Override
	protected void afterRemove(Node<E> node) {
		// 如果删除的节点是红色
		// 或者 用以取代删除节点的子节点是红色
		if (isRed(node)) {
			black(node);
			return;
		}
		
		Node<E> parent = node.parent;
		// 删除的是根节点
		if (parent == null) return;
		
		// 删除的是黑色叶子节点【下溢】
		// 判断被删除的node是左还是右
		boolean left = parent.left == null || node.isLeftChild();
		Node<E> sibling = left ? parent.right : parent.left;
		if (left) { // 被删除的节点在左边,兄弟节点在右边
			if (isRed(sibling)) { // 兄弟节点是红色
				black(sibling);
				red(parent);
				rotateLeft(parent);
				// 更换兄弟
				sibling = parent.right;
			}
			
			// 兄弟节点必然是黑色
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并
				boolean parentBlack = isBlack(parent);
				black(parent);
				red(sibling);
				if (parentBlack) {
					afterRemove(parent);
				}
			} else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素
				// 兄弟节点的左边是黑色,兄弟要先旋转
				if (isBlack(sibling.right)) {
					rotateRight(sibling);
					sibling = parent.right;
				}
				
				color(sibling, colorOf(parent));
				black(sibling.right);
				black(parent);
				rotateLeft(parent);
			}
		} else { // 被删除的节点在右边,兄弟节点在左边
			if (isRed(sibling)) { // 兄弟节点是红色
				black(sibling);
				red(parent);
				rotateRight(parent);
				// 更换兄弟
				sibling = parent.left;
			}
			
			// 兄弟节点必然是黑色
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并
				boolean parentBlack = isBlack(parent);
				black(parent);
				red(sibling);
				if (parentBlack) {
					afterRemove(parent);
				}
			} else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素
				// 兄弟节点的左边是黑色,兄弟要先旋转
				if (isBlack(sibling.left)) {
					rotateLeft(sibling);
					sibling = parent.left;
				}
				
				color(sibling, colorOf(parent));
				black(sibling.left);
				black(parent);
				rotateRight(parent);
			}
		}
	}

	private Node<E> color(Node<E> node, boolean color) {
		if (node == null) return node;
		((RBNode<E>)node).color = color;
		return node;
	}
	
	private Node<E> red(Node<E> node) {
		return color(node, RED);
	}
	
	private Node<E> black(Node<E> node) {
		return color(node, BLACK);
	}
	
	private boolean colorOf(Node<E> node) {
		return node == null ? BLACK : ((RBNode<E>)node).color;
	}
	
	private boolean isBlack(Node<E> node) {
		return colorOf(node) == BLACK;
	}
	
	private boolean isRed(Node<E> node) {
		return colorOf(node) == RED;
	}
	
	@Override
	protected Node<E> createNode(E element, Node<E> parent) {
		return new RBNode<>(element, parent);
	}

	private static class RBNode<E> extends Node<E> {
		boolean color = RED;
		public RBNode(E element, Node<E> parent) {
			super(element, parent);
		}
		
		@Override
		public String toString() {
			String str = "";
			if (color == RED) {
				str = "R_";
			}
			return str + element.toString();
		}
	}
}

添加

构建红黑树的时候,心中一定要有B树.先要进行构建一个B树之后才能够进行构建一个红黑树.

已知
B树中,新元素必定是添加到叶子节点中
4阶B树所有节点的元素个数 x 都符合 1 ≤ x ≤ 3
建议新添加的节点默认为 RED ,这样能够让红黑树的性质尽快满足(性质 1、2、3、5 都满足,性质 4 不一定)RED节点的parent都是BLANK.

如果添加的是根节点,染成 BLACK 即可.

 添加的所有情况

红黑树之中没有平衡因子这个概念的,就是不存在相应的一个失衡的过程,只要维护好红黑树的五条性质就好了. 

添加 - 修复性质4 - LL\RR

其中的六种情况不管,只关心其中的两种情况.

判定条件: uncle 不是 RED
1. parent 染成 BLACK grand 染成 RED
2. grand 进行单旋操作
LL:右旋转
RR:左旋转

在B树之中相应的黑色节点是相应的父节点,所以指出来的一般都是相应的红色的节点.

添加 – 修复性质4 – LR\RL

 添加 – 修复性质4 – 上溢 – LL

上面的25是需要将它看成是新添加的节点进行看待,如果要是上溢的话,之间进行一个染色的操作,是不需要旋转的操作.

 添加 – 修复性质4 – 上溢 – LL

添加 – 修复性质4 – 上溢 – LR

添加 – 修复性质4 – 上溢 – RL 

 

 

本文含有隐藏内容,请 开通VIP 后查看