写在前面
今儿个周末,终于有时间把前两天写的关于红黑树删除部分的代码进行测试,现在测试完了,暂没有发现问题,所以将代码分享出来,供大家参考学习.
注意:这次的检验与删除部分跟之前的查找和插入部分一脉相承,所以重复的部分我就不粘出来了,大家可以两篇文章一起看.
具体包已经上传,免费下载RedBlackTree.zip
水平有限,难免疏漏,欢迎指正.
代码部分
运行环境
jdk1.8
intellij idea ultimate 2020.2
检查红黑树是否合法
/**
* 检查红黑树是否合法
*
*/
public boolean checkTree() {
TreeNode<V> node = rootNode;
int number = 0;
int blackNums1 = 0;
int blackNums2;
int count = 0;
boolean isRedBlackTree = true;
Map map = new HashMap<>();
// 如果是空树
if (node != null) {
if (node.isRoot() && node.isRed()) {
isRedBlackTree = false;
}else {
checkTreeMethod(node, number, map);
}
}
for (Object key : map.keySet()) {
count++;
if (count == 1) {
blackNums1 = (int) map.get(key);
}else {
blackNums2 = (int) map.get(key);
if (blackNums1 != blackNums2) {
System.out.println("当前路径" + key + "上的黑色节点数是: " + map.get(key));
System.out.println("但是其它路径上的黑色节点数是: " + blackNums1);
isRedBlackTree = false;
break;
}
}
}
return isRedBlackTree;
}
private void checkTreeMethod(TreeNode<V> node, int number, Map map) {
if (!node.isRed()) {
number++;
}
if (node.getLeft() != null) {
checkTreeMethod(node.getLeft(), number, map);
}else {
map.put(node.getKey() + "'s left", number);
}
if (node.getRight() != null) {
checkTreeMethod(node.getRight(), number, map);
}else {
map.put(node.getKey() + "'s right", number);
}
}
删除节点
package com.srt.orange.test.Tree;
import java.util.HashMap;
import java.util.Map;
/**
* @author: cuijr
* @email:
* @date: 2020-11-10 15:08
* @description:
*/
public class RedBlackTree<V> {
// 树的根节点
private TreeNode<V> rootNode;
/**
* 查找
* @param key
* @param currentNode: the root node of the tree which you want to use
*/
public TreeNode<V> find(int key,TreeNode<V> currentNode) {
TreeNode<V> node = null;
if (currentNode != null) {
if (currentNode.getKey() == key) {
return currentNode;
}else if (currentNode.getKey() > key) {
return find(key, currentNode.getLeft());
}else {
return find(key, currentNode.getRight());
}
}
return node;
}
// turn left
// node is the pivot
private void turnLeft(TreeNode<V> node) throws CanNotTurnLeft {
TreeNode<V> temp = null;
if (node == null || node.getParent() == null) {
throw new CanNotTurnLeft("you cannot turn left because short of valid treenode");
}else {
temp = node.getLeft();
node.setLeft(node.getParent());
node.setParent(node.getLeft().getParent());
node.setLeft(node.getLeft().isLeft());
node.getLeft().setParent(node);
node.getLeft().setLeft(true);
node.getLeft().setRight(temp);
if (node.getParent() == null) {
node.setRoot(true);
node.getLeft().setRoot(false);
this.rootNode = node;
}else {
if (node.isLeft()) {
node.getParent().setLeft(node);
}else {
node.getParent().setRight(node);
}
}
if (temp != null) {
temp.setLeft(false);
temp.setParent(node.getLeft());
}
}
}
// trun right
// node is the pivot
private void turnRight(TreeNode<V> node) throws CanNotTurnRight {
TreeNode<V> temp;
if (node == null || node.getParent() == null) {
throw new CanNotTurnRight("you cannot turn right because short of valid treenode");
}else {
temp = node.getRight();
node.setRight(node.getParent());
node.setParent(node.getRight().getParent());
node.setLeft(node.getRight().isLeft());
node.getRight().setParent(node);
node.getRight().setLeft(false);
node.getRight().setLeft(temp);
// 如果旋转后支点变成了根节点,那么需要修改它的属性和原根节点的属性
if (node.getParent() == null) {
node.setRoot(true);
node.getRight().setRoot(false);
this.rootNode = node;
}else {
// 如果旋转后支点不是根节点,那么还需要将支点的父节点的左子节点或右子节点改为本支点
if (node.isLeft()) {
node.getParent().setLeft(node);
}else {
node.getParent().setRight(node);
}
}
if (temp != null) {
temp.setLeft(true);
temp.setParent(node.getRight());
}
}
}
/**
* 输出整棵树
* @param node
* @param number
*/
public void printLikeTree(TreeNode<V> node, int number) throws TreeIsNotValidException {
if (node == null) {
return;
}
for (int i = 1; i <= number; i++) {
System.out.print("------|");
}
System.out.format((node.isLeft() ? "左" : "右") + (node.isRed() ? "红" : "黑") + "%-4d\n", node.getKey());
printLikeTree(node.getLeft(), ++number);
number--;
printLikeTree(node.getRight(), ++number);
number--;
}
public TreeNode<V> getRootNode() {
return rootNode;
}
public void delete(int key) throws CanNotDeleteNode, TreeIsNotValidException, CanNotTurnLeft, CanNotTurnRight {
TreeNode<V> currentNode = find(key, rootNode);
// 如果不存在
if (currentNode == null) {
return;
}
// 情况1 红色
if (currentNode.isRed()) {
// 情况1.1 没有子节点
if (currentNode.getRight() == null && currentNode.getLeft() == null) {
deleteSelf(currentNode);
}
// 情况1.3 有两个子节点
else if (currentNode.getRight() != null && currentNode.getLeft() != null) {
TreeNode<V> oldNode = currentNode;
currentNode = findNext(currentNode);
delete(currentNode.getKey());
oldNode.setKey(currentNode.getKey());
}
// 情况1.2 有一个子节点
else {
throw new TreeIsNotValidException("红色节点不可能只要一个子节点,当前节点的key为: " + currentNode.getKey());
}
}
// 情况2 黑色
else {
// 情况2.1 没有子节点
if (currentNode.getRight() == null && currentNode.getLeft() == null) {
// 如果是根节点
if (currentNode.isRoot()) {
rootNode = null;
return;
}
deleteNoneChildBlack(currentNode);
}
// 情况2.3 有两个子节点
else if (currentNode.getRight() != null && currentNode.getLeft() != null) {
TreeNode<V> oldNode = currentNode;
currentNode = findNext(currentNode);
delete(currentNode.getKey());
oldNode.setKey(currentNode.getKey());
}
//情况2.2 有一个子节点
else {
deleteOneChildBlack(currentNode);
}
}
}
// 删除当前节点
private boolean deleteSelf(TreeNode<V> node) throws CanNotDeleteNode {
boolean isSuccess = false;
if (node.getParent() == null) {
throw new CanNotDeleteNode("this node ha