BTree概念及RBTree实现(JAVA)

B树:

在实现红黑树之前先了解一下B树,因为红黑树的一些操作的实现和B树关系密切。

B树概念:
在这里插入图片描述在这里插入图片描述

m阶b树的性质(m>=2)
在这里插入图片描述ps:b树里面只有叶子节点和度>=2的节点

b树的搜索
在这里插入图片描述

b树的添加
在这里插入图片描述

m阶b树添加上溢
当一个节点的元素个数等于m时会造成添加上溢
在这里插入图片描述

m阶b树删除

a 删除的节点是叶子节点
在这里插入图片描述

b 删除的节点是非叶子节点
在这里插入图片描述

c 删除下溢
在这里插入图片描述在这里插入图片描述注意:将父节点元素b挪下来和左右子节点合并,可能会导致父节点下溢,且这个情况可能会一直向上延续

红黑树

前述
AVL树的删除元素后恢复平衡的操作的时间复杂度可能是O(logn)级别的,可以对其进一步优化,所以红黑树应运而生(它的添加,删除,搜索平均时间度复杂都是O(logn) ,添加和删除后的恢复平衡操作是O(1)级别的)

红黑树的定义
在这里插入图片描述红黑树和四阶B树的的等价性
在这里插入图片描述红黑树等价成四阶B树后,该四阶B树的节点有以下四种可能:
在这里插入图片描述添加
在这里插入图片描述注意1:二叉搜素树新元素添加不一定添加到叶子节点,可能添加到度为1的节点
注意2:新添加的节点默认是红色这样能使红黑树的性质尽快满足
注意3:红黑树的添加是基于二叉搜索树的添加方法,不同的是在每个元素被添加后,红黑树都需要进行维护即使这棵树满足红黑树的五条性质(类似于AVLTree的添加后的操作)

节点代码

private class RBNode<T> extends Node<T> {
		// 默认是红色
		private boolean color = RED;

		public RBNode(T element, Node<T> parent) {
			super(element, parent);

		}

		@Override
		public String toString() {
			if (parent != null) {

				return element + ":" + (color == true ? "r" : "h") + " p:" + parent.element;

			}
			return element + ":" + (color == true ? "r" : "h") + " p:";

		}

	}

添加的12种情况
因为红黑树是等价于四阶B树的,所以它等价的四阶B树的节点只有四种可能(上面有分析)。又因为B树添加元素都是添加到叶子节点,所有添加的所有情况就是下图的12种。(sibling:兄弟节点 parent:父节点 uncle:叔父节点(parent的兄弟节点) grand:祖父节点)
在这里插入图片描述parent为黑色(四种)
不需要做任何处理

parent为红色(8种)
a:uncle是黑色 (null 默认是黑色) 4种情况
这四种情况是类似于AVLTree里的旋转操作。
LL /RR情况
在这里插入图片描述LR/RL情况
在这里插入图片描述

b:uncle是红色 (null 默认是黑色) 4种情况
这四种情况在等价的四阶B树中是会产生上溢的,解决办法类似于B树的添加上溢(将中间元素向上合并,中间元素的左右两边的元素变成它的两个左右子节点),不同的是在红黑树中只是对一些节点进行染色而在它等价的四阶B树中是进行了元素的向上合并。
在这里插入图片描述add代码

// 添加元素 默认大的放在右边 小的反在左边
	// 也可以自己传入比较器
	public T add(T element) {

		// 判断是否有根节点
		if (root == null) {
			root = createNode(element, null);
			size++;
			afterAdd(root);
			return null;
		} else {
			Node<T> node = root;
			Node<T> parent = null;

			int result = 0;
			// 一直遍历 直到最后一层
			while (node != null) {
				parent = node;
				result = compare(element, node.element);
				if (result > 0) {

					node = node.right;
				} else if (result < 0) {
					node = node.left;
				} else {

					return node.element;
				}
			}
			// 根据结果判断是添加到右子树还是左子树
			Node<T> newNode = createNode(element, parent);
			if (result > 0) {

				parent.right = newNode;
				size++;

			} else {
				parent.left = newNode;
				size++;

			}
			afterAdd(newNode);
			return parent.element;
		}
	}

afteradd代码

// 添加元素后要进行的操作
	@Override
	protected void afterAdd(Node<T> node) {
		// 添加的是根节点
		if (node.parent == null) {
			black(node);

			return;
		}
		// 父节点是黑色
		if (isBlack(node.parent)) {

			return;
		} else {// 父节点不是黑色
			// 祖父节点
			Node<T> grand = node.parent.parent;
			// 父节点
			Node<T> parent = node.parent;
			// 叔父节点是红色  在四阶B树中会产生上溢
			if (isRed(node.parent.getSibling())) {
				black(parent);
				black(parent.getSibling());
				//将向上合并的节点当作一个新添加的节点去操作
				afterAdd(red(grand));
				return;
			}
			// 叔父节点不是红色
			// L
			if (node.parent.isLeftNode()) {
				// LL
				red(grand);

				if (node.isLeftNode()) {
					black(node.parent);

				} else {// LR
					black(node);
					rotateleft(parent);

				}
				rotateRight(grand);
			} else {// R
				red(grand);

				// RL
				if (node.isLeftNode()) {
					black(node);

					rotateRight(parent);
					rotateleft(grand);
				} else {// RR

					black(parent);
					rotateleft(grand);

				}

			}

		}

	}

删除
上面分析过红黑树等价的四阶B树的节点情况只有四种.B树的真正删除只会在叶子节点中进行也就是最后一层。所以可以分成以下二种情况来讨论.

**删除的节点是红色 **
例如删除的是17,33,50,72
在这里插入图片描述
在这里插入图片描述删除的节点是黑色 (3种情况)
在这里插入图片描述a:删除拥有一个红色子节点的黑色子节点
例如删除46,76
在这里插入图片描述
在这里插入图片描述
b.删除黑色叶子节点
在等价的四阶B树中被删除的黑色叶子节点有12种可能(和添加类似的分析),这12种可能是对称的,根据在父节点左右划分各6种。下面对黑色叶子节点是父节点的右子节点进行讨论。
【88是要被删除的黑色叶子节点】
1.兄弟节点是红色(包含1种种情况)
在这里插入图片描述2 兄弟节点是黑色的(包含5种情况)
兄 节点
在这里插入图片描述兄弟节点没有红色子节点
在这里插入图片描述remove代码

// 移除元素
	public void remove(T element) {
		Node<T> node = getNode(element);
		remove(node);

	}

	/**
	 * 移除元素后要进行的操作
	 * 
	 * @param node 删除的节点或者是用于替代的节点
	 *
	 */
	protected void afterRemove(Node<T> node) {

	}

	// 根据元素找到节点
	private Node<T> getNode(T element) {
		Node<T> node = root;
		while (node != null) {
			int result = compare(node.element, element);
			if (result == 0) {
				return node;
			} else if (result < 0) {
				node = node.right;

			} else {
				node = node.left;
			}
		}
		return null;
	}

	// 移除节点
	private void remove(Node<T> node) {
		// 用于取代的节点
		Node<T> replace;
		// 删除节点度为2的节点
		if (node.hasTwoChildren()) {
			// 直接将它的前驱节点的值赋给该节点 然后删除前驱节点
			node.element = getpredecessor(node).element;
			// 前驱节点 后继节点的度只能为1 或者0
			// 所以直接赋值给node 通过后续删除度为0或1节点来间接删除
			node = getpredecessor(node);
		}
		// 删除度为0或1的节点
		if (node.isLeaf()) {
			if (node.parent == null) {
				root = null;
				return;
			} else {
				if (node.isLeftNode()) {
					node.parent.left = null;

				} else {
					node.parent.right = null;

				}
				size--;
				// node是被删除的节点
				afterRemove(node);
				return;
			}
		} else {

			if (node.parent == null) {
				if (node.left != null) {
					replace = node.left;
					root = replace;

				} else {
					replace = node.right;
					root = replace;

				}

			} else {

				if (node.isLeftNode()) {
					if (node.left != null) {
						replace = node.left;
						replace.parent = node.parent;
						node.parent.left = replace;
					} else {
						replace = node.right;
						replace.parent = node.parent;
						node.parent.left = replace;
					}

				} else {
					if (node.left != null) {
						replace = node.left;
						replace.parent = node.parent;
						node.parent.left = replace;
					} else {
						replace = node.right;
						replace.parent = node.parent;
						node.parent.left = replace;
					}
				}

			}
			size--;
			//replace是替代节点
			afterRemove(replace);
			return;
		}

	}

affterRemove代码

    
	// 传入一个参数的afterRemove方法   该参数既可以是被删除节点也可以是替代节点
	// 删除度为2的节点会去删除它的前驱或后继节点
	// 所以其实真正被删除的节点只有可能是度为0或1的节点
	protected void afterRemove(Node<T> node) {
		// 被删除节点的父节点
		Node<T> parent = node.parent;

		// 被删除的节点是根节点
		if (parent == null)
			return;

		// 如果替代节点是红色或者被删除的节点是红色
		if (isRed(node)) {
			black(node);
			return;
		}

		// 被删除的节点是黑色叶子节点

		// 判断被删除的节点是左节点还是右节点
		boolean left = parent.left == null || node.isLeftNode();
		// 获取兄弟节点
		Node<T> sibling = left ? parent.right : parent.left;

		// 黑色叶子节点的两种可能代码是对称的
		// 黑色叶子节点是右节点
		if (!left) {

			// 兄弟节点是红色
			if (isRed(sibling)) {

				red(parent);
				black(sibling);

				rotateRight(parent);
				// 更换兄弟节点
				sibling = parent.left;
			}

			// 兄弟节点是黑色

			// 兄弟节点没有一个红色子节点
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 父节点的颜色是否为黑色
				boolean parentColor = isBlack(parent);
				// 将父节点变成黑色
				black(parent);
				// 将兄弟节点变成红色
				red(sibling);
				if (parentColor) {
					afterRemove(parent);
					return;
				}

			} else {
				// 兄弟节点至少有一个红色子节点

				// 兄弟节点的左子节点是黑色
				if (isBlack(sibling.left)) {

					rotateleft(sibling);
					sibling = parent.left;
					

				}
				changeColor(sibling, colorOf(parent));
				black(parent);
				black(sibling.left);
				rotateRight(parent);

			}

		} else {
			// 黑色叶子节点是左节点


			// 兄弟节点是红色
			if (isRed(sibling)) {

				red(parent);
				black(sibling);

				rotateleft(parent);
				// 更换兄弟节点
				sibling = parent.right;
			}

			// 兄弟节点是黑色

			// 兄弟节点没有一个红色子节点
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 父节点的颜色是否为黑色
				boolean parentColor = isBlack(parent);
				// 将父节点变成黑色
				black(parent);
				// 将兄弟节点变成红色
				red(sibling);
				if (parentColor) {
					afterRemove(parent);
					return;
				}

			} else {
				// 兄弟节点至少有一个红色子节点

				// 兄弟节点的左子节点是黑色
				if (isBlack(sibling.right)) {

					rotateRight(sibling);
					sibling = parent.right;
					

				}
				changeColor(sibling, colorOf(parent));
				black(parent);
				black(sibling.right);
				rotateleft(parent);

			}
		}

	}


	// 传入两个参数的afterRemove方法
	// 删除度为2的节点会去删除它的前驱或后继节点
	// 所以其实真正被删除的节点只有可能是度为0或1的节点
	protected void afterRemove1(Node<T> node, Node<T> replace) {
		// 被删除节点的父节点
		Node<T> parent = node.parent;
		// 被删除的节点是红色
		if (isRed(node))
			return;

		// 被删除的节点是根节点
		if (parent == null)
			return;

		// 如果替代节点是红色
		if (isRed(replace)) {
			black(replace);
			return;
		}

		// 被删除的节点是黑色叶子节点

		// 判断被删除的节点是左节点还是右节点
		boolean left = parent.left == null || node.isLeftNode();
		// 获取兄弟节点
		Node<T> sibling = left ? parent.right : parent.left;

		// 黑色叶子节点的两种可能代码是对称的
		// 黑色叶子节点是右节点
		if (!left) {

			// 兄弟节点是红色
			if (isRed(sibling)) {

				red(parent);
				black(sibling);

				rotateRight(parent);
				// 更换兄弟节点
				sibling = parent.left;
			}

			// 兄弟节点是黑色

			// 兄弟节点没有一个红色子节点
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 父节点的颜色是否为黑色
				boolean parentColor = isBlack(parent);
				// 将父节点变成黑色
				black(parent);
				// 将兄弟节点变成红色
				red(sibling);
				//父节点原先颜色是黑色 则将父节点传入afteRemove方法来维持红黑树性质  
				if (parentColor) {
					afterRemove(parent);
					return;
				}

			} else {
				// 兄弟节点至少有一个红色子节点

				// 兄弟节点的左子节点是黑色
				if (isBlack(sibling.left)) {

					rotateleft(sibling);
					sibling = parent.left;

				}
				changeColor(sibling, colorOf(parent));
				black(parent);
				black(sibling.left);
				rotateRight(parent);

			}

		} else {
			// 黑色叶子节点是左节点


			// 兄弟节点是红色
			if (isRed(sibling)) {

				red(parent);
				black(sibling);

				rotateleft(parent);
				// 更换兄弟节点
				sibling = parent.right;
			}

			// 兄弟节点是黑色

			// 兄弟节点没有一个红色子节点
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 父节点的颜色是否为黑色
				boolean parentColor = isBlack(parent);
				// 将父节点变成黑色
				black(parent);
				// 将兄弟节点变成红色
				red(sibling);
				//父节点原先颜色是黑色 则将父节点传入afteRemove方法来维持红黑树性质  
				if (parentColor) {
					afterRemove(parent);
					return;
				}

			} else {
				// 兄弟节点至少有一个红色子节点

				// 兄弟节点的左子节点是黑色
				if (isBlack(sibling.right)) {

					rotateRight(sibling);
					sibling = parent.right;

				}
				changeColor(sibling, colorOf(parent));
				black(parent);
				black(sibling.right);
				rotateleft(parent);

			}
		}

	}

}

为啥维持那五条性质红黑树就能保持平衡
在这里插入图片描述

红黑树的平均时间复杂度
在这里插入图片描述红黑树和AVL树的对比
在这里插入图片描述
RBTree代码

package com.ldg.tree;

public class RBTree<T> extends BalanceBinarySearchTree<T> {
	// 颜色常量
	private static final boolean RED = true;
	private static final boolean BLACK = false;

	private class RBNode<T> extends Node<T> {
		// 默认是红色
		private boolean color = RED;

		public RBNode(T element, Node<T> parent) {
			super(element, parent);

		}

		@Override
		public String toString() {
			if (parent != null) {

				return element + ":" + (color == true ? "r" : "h") + " p:" + parent.element;

			}
			return element + ":" + (color == true ? "r" : "h") + " p:";

		}

	}

	/**
	 * 判断节点的颜色 空节点默认是黑色的
	 * 
	 * @param node
	 * @return false:黑色 , true:红色
	 */
	private boolean colorOf(Node<T> node) {
		return node == null ? BLACK : ((RBNode) node).color;
	}

	/**
	 * 判断节点是否为黑色
	 * 
	 * @param node
	 * @return
	 */
	private boolean isBlack(Node<T> node) {
		return colorOf(node) == BLACK;
	}

	/**
	 * 判断节点是否为红色
	 * 
	 * @param node
	 * @return
	 */
	private boolean isRed(Node<T> node) {
		return colorOf(node) == RED;
	}

	/**
	 * 改变节点的颜色
	 * 
	 * @param node
	 * @param color
	 * @return 返回改变后的节点
	 */
	private RBNode<T> changeColor(Node<T> node, boolean color) {
		if (node != null)
			((RBNode) node).color = color;
		return (RBNode) node;
	}

	/**
	 * 将节点变成黑色
	 * 
	 * @param node
	 * @return
	 */
	private RBNode<T> black(Node<T> node) {
		return changeColor(node, BLACK);
	}

	/**
	 * 将节点变成红色
	 * 
	 * @param node
	 * @return
	 */
	private RBNode<T> red(Node<T> node) {
		return changeColor(node, RED);
	}

	// 创建自己的子节点
	@Override
	protected Node<T> createNode(T element, Node<T> parent) {

		return new RBNode(element, parent);
	}

	// 添加元素后要进行的操作
	@Override
	protected void afterAdd(Node<T> node) {
		// 添加的是根节点
		if (node.parent == null) {
			black(node);

			return;
		}
		// 父节点是黑色
		if (isBlack(node.parent)) {

			return;
		} else {// 父节点不是黑色
			// 祖父节点
			Node<T> grand = node.parent.parent;
			// 父节点
			Node<T> parent = node.parent;
			// 叔父节点是红色
			if (isRed(node.parent.getSibling())) {
				black(parent);
				black(parent.getSibling());
				afterAdd(red(grand));
				return;
			}
			// 叔父节点不是红色
			// L
			if (node.parent.isLeftNode()) {
				// LL
				red(grand);

				if (node.isLeftNode()) {
					black(node.parent);

				} else {// LR
					black(node);
					rotateleft(parent);

				}
				rotateRight(grand);
			} else {// R
				red(grand);

				// RL
				if (node.isLeftNode()) {
					black(node);

					rotateRight(parent);
					rotateleft(grand);
				} else {// RR

					black(parent);
					rotateleft(grand);

				}

			}

		}

	}

	// 传入一个参数的afterRemove方法   该参数既可以是被删除节点也可以是替代节点
	// 删除度为2的节点会去删除它的前驱或后继节点
	// 所以其实真正被删除的节点只有可能是度为0或1的节点
	protected void afterRemove(Node<T> node) {
		// 被删除节点的父节点
		Node<T> parent = node.parent;

		// 被删除的节点是根节点
		if (parent == null)
			return;

		// 如果替代节点是红色或者被删除的节点是红色
		if (isRed(node)) {
			black(node);
			return;
		}

		// 被删除的节点是黑色叶子节点

		// 判断被删除的节点是左节点还是右节点
		boolean left = parent.left == null || node.isLeftNode();
		// 获取兄弟节点
		Node<T> sibling = left ? parent.right : parent.left;

		// 黑色叶子节点的两种可能代码是对称的
		// 黑色叶子节点是右节点
		if (!left) {

			// 兄弟节点是红色
			if (isRed(sibling)) {

				red(parent);
				black(sibling);

				rotateRight(parent);
				// 更换兄弟节点
				sibling = parent.left;
			}

			// 兄弟节点是黑色

			// 兄弟节点没有一个红色子节点
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 父节点的颜色是否为黑色
				boolean parentColor = isBlack(parent);
				// 将父节点变成黑色
				black(parent);
				// 将兄弟节点变成红色
				red(sibling);
				if (parentColor) {
					afterRemove(parent);
					return;
				}

			} else {
				// 兄弟节点至少有一个红色子节点

				// 兄弟节点的左子节点是黑色
				if (isBlack(sibling.left)) {

					rotateleft(sibling);
					sibling = parent.left;
					

				}
				changeColor(sibling, colorOf(parent));
				black(parent);
				black(sibling.left);
				rotateRight(parent);

			}

		} else {
			// 黑色叶子节点是左节点


			// 兄弟节点是红色
			if (isRed(sibling)) {

				red(parent);
				black(sibling);

				rotateleft(parent);
				// 更换兄弟节点
				sibling = parent.right;
			}

			// 兄弟节点是黑色

			// 兄弟节点没有一个红色子节点
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 父节点的颜色是否为黑色
				boolean parentColor = isBlack(parent);
				// 将父节点变成黑色
				black(parent);
				// 将兄弟节点变成红色
				red(sibling);
				if (parentColor) {
					afterRemove(parent);
					return;
				}

			} else {
				// 兄弟节点至少有一个红色子节点

				// 兄弟节点的左子节点是黑色
				if (isBlack(sibling.right)) {

					rotateRight(sibling);
					sibling = parent.right;
					

				}
				changeColor(sibling, colorOf(parent));
				black(parent);
				black(sibling.right);
				rotateleft(parent);

			}
		}

	}

	// 传入两个参数的afterRemove方法
	// 删除度为2的节点会去删除它的前驱或后继节点
	// 所以其实真正被删除的节点只有可能是度为0或1的节点
	protected void afterRemove1(Node<T> node, Node<T> replace) {
		// 被删除节点的父节点
		Node<T> parent = node.parent;
		// 被删除的节点是红色
		if (isRed(node))
			return;

		// 被删除的节点是根节点
		if (parent == null)
			return;

		// 如果替代节点是红色
		if (isRed(replace)) {
			black(replace);
			return;
		}

		// 被删除的节点是黑色叶子节点

		// 判断被删除的节点是左节点还是右节点
		boolean left = parent.left == null || node.isLeftNode();
		// 获取兄弟节点
		Node<T> sibling = left ? parent.right : parent.left;

		// 黑色叶子节点的两种可能代码是对称的
		// 黑色叶子节点是右节点
		if (!left) {

			// 兄弟节点是红色
			if (isRed(sibling)) {

				red(parent);
				black(sibling);

				rotateRight(parent);
				// 更换兄弟节点
				sibling = parent.left;
			}

			// 兄弟节点是黑色

			// 兄弟节点没有一个红色子节点
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 父节点的颜色是否为黑色
				boolean parentColor = isBlack(parent);
				// 将父节点变成黑色
				black(parent);
				// 将兄弟节点变成红色
				red(sibling);
				//父节点原先颜色是黑色 则将父节点传入afteRemove方法来维持红黑树性质  
				if (parentColor) {
					afterRemove(parent);
					return;
				}

			} else {
				// 兄弟节点至少有一个红色子节点

				// 兄弟节点的左子节点是黑色
				if (isBlack(sibling.left)) {

					rotateleft(sibling);
					sibling = parent.left;

				}
				changeColor(sibling, colorOf(parent));
				black(parent);
				black(sibling.left);
				rotateRight(parent);

			}

		} else {
			// 黑色叶子节点是左节点


			// 兄弟节点是红色
			if (isRed(sibling)) {

				red(parent);
				black(sibling);

				rotateleft(parent);
				// 更换兄弟节点
				sibling = parent.right;
			}

			// 兄弟节点是黑色

			// 兄弟节点没有一个红色子节点
			if (isBlack(sibling.left) && isBlack(sibling.right)) {
				// 父节点的颜色是否为黑色
				boolean parentColor = isBlack(parent);
				// 将父节点变成黑色
				black(parent);
				// 将兄弟节点变成红色
				red(sibling);
				//父节点原先颜色是黑色 则将父节点传入afteRemove方法来维持红黑树性质  
				if (parentColor) {
					afterRemove(parent);
					return;
				}

			} else {
				// 兄弟节点至少有一个红色子节点

				// 兄弟节点的左子节点是黑色
				if (isBlack(sibling.right)) {

					rotateRight(sibling);
					sibling = parent.right;

				}
				changeColor(sibling, colorOf(parent));
				black(parent);
				black(sibling.right);
				rotateleft(parent);

			}
		}

	}

}


运行效果
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值