红黑树五个性质(可以参考维基百科)
- 节点是红色或者黑色
- 根节点是黑色
- 叶子节点颜色为黑色(不是NULL节点,是自己构造的黑色叶子结点)
- 红色节点的孩子节点是黑色
- 从某个节点到其叶子结点的黑色节点个数相同
红黑树的插入和删除操作就是为了保证这五个性质,特别是性质4、5。因此,为了保证插入不破坏性质5,插入时节点颜色默认为红色
红黑树节点数据结构
package com.xll.tree.redblack;
/**
* @Author: xialonglei469
* @Date: 2019-9-24 14:38
* @Version 1.0
*
* 红黑树节点数据结构
*/
public class Node {
private int data;
private Node lc;
private Node rc;
private Node parent;
/** 红色 */
public final static int RED = 1;
/** 黑色 */
public final static int BLACK = 2;
/** 充当叶子节点,叶子节点不为NULL */
public final static Node LEAF_NODE = new Node(BLACK);
/** 节点颜色 */
private int color = RED;
public Node() {}
public Node(int color) {
this.color = color;
}
public Node(int data , Node parent) {
this.data = data;
this.parent = parent;
}
public Node(int data , int color , Node parent) {
this.data = data;
this.color = color;
this.parent = parent;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getLc() {
return lc;
}
public void setLc(Node lc) {
this.lc = lc;
}
public Node getRc() {
return rc;
}
public void setRc(Node rc) {
this.rc = rc;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
}
红黑树实现
package com.xll.tree.redblack;
/**
* @Author: xialonglei469
* @Date: 2019-9-24 14:44
* @Version 1.0
*
* 红黑树
*/
public class RedBlackTree {
/** 红黑书根节点,颜色为黑色 */
private Node root;
/**
* 获取祖父节点
*/
public Node grandparent(Node node) {
return node.getParent().getParent();
}
/**
* 获取兄弟节点
*/
public Node sibling(Node node) {
if (node == node.getParent().getLc()) {
return node.getParent().getRc();
} else {
return node.getParent().getLc();
}
}
/**
* 获取叔父节点
*/
public Node uncle(Node node) {
if (node.getParent() == grandparent(node).getLc()) {
return grandparent(node).getRc();
} else {
return grandparent(node).getLc();
}
}
/**
* 节点插入
*/
public Node insert(int data) {
Node node = executeInsert(data);
insertAdjust0(node);
return node;
}
/**
* 节点删除
*/
public Node delete(int data , Node node) {
if (node == Node.LEAF_NODE) {
return null;
}
int nodeData = node.getData();
if (nodeData > data) {
return delete(data , node.getLc());
} else if (nodeData < data) {
return delete(data , node.getRc());
} else {
if (node.getRc() == Node.LEAF_NODE) {
deleteOneChild(node);
} else {
Node rcSmallestChild = getRcSmallestChild(node.getRc());
node.setData(rcSmallestChild.getData());
deleteOneChild(rcSmallestChild);
}
}
return node;
}
private Node getRcSmallestChild(Node rc) {
if (rc.getLc() == Node.LEAF_NODE) {
return rc;
}
return getRcSmallestChild(rc.getLc());
}
private void deleteOneChild(Node node) {
Node lc = node.getLc();
Node rc = node.getRc();
Node child = lc != Node.LEAF_NODE ? lc : rc;
Node parent = node.getParent();
if (parent == null &&
lc == Node.LEAF_NODE &&
rc == Node.LEAF_NODE) {
root = null;
return;
}
if (parent == null) {
root = child;
child.setColor(Node.BLACK);
child.setParent(null);
return;
}
if (parent.getLc() == node) {
parent.setLc(child);
} else {
parent.setRc(child);
}
child.setParent(parent);
// 如果删除节点为红色,则不做任何操作
// 如果删除节点为黑色
if (node.getColor() == Node.BLACK) {
if (child.getColor() == Node.RED) {
child.setColor(Node.BLACK);
} else {
deleteAdjust0(child);
}
}
}
private void deleteAdjust0(Node node) {
if (node.getParent() == null) {
return;
}
Node sibling = sibling(node);
Node parent = node.getParent();
if (sibling.getColor() == Node.RED) {
parent.setColor(Node.RED);
sibling.setColor(Node.BLACK);
if (node == parent.getLc()) {
rotateRight(parent);
} else {
rotateLeft(parent);
}
}
deleteAdjust1(node);
}
private void deleteAdjust1(Node node) {
Node sibling = sibling(node);
if (node.getParent().getColor() == Node.BLACK &&
sibling.getColor() == Node.BLACK &&
sibling.getLc().getColor() == Node.BLACK &&
sibling.getRc().getColor() == Node.BLACK) {
sibling.setColor(Node.RED);
deleteAdjust0(node.getParent());
} else {
deleteAdjust2(node);
}
}
private void deleteAdjust2(Node node) {
Node sibling = sibling(node);
if (node.getParent().getColor() == Node.RED &&
sibling.getColor() == Node.BLACK &&
sibling.getLc().getColor() == Node.BLACK &&
sibling.getRc().getColor() == Node.BLACK) {
sibling.setColor(Node.RED);
node.getParent().setColor(Node.BLACK);
} else {
deleteAdjust3(node);
}
}
private void deleteAdjust3(Node node) {
Node parent = node.getParent();
Node sibling = sibling(node);
Node sLc = sibling.getLc();
Node sRc = sibling.getRc();
if (sibling.getColor() == Node.BLACK) {
if (parent.getLc() == node &&
sLc.getColor() == Node.RED &&
sRc.getColor() == Node.BLACK) {
sLc.setColor(Node.BLACK);
sibling.setColor(Node.RED);
rotateRight(sibling);
} else if (parent.getRc() == node &&
sLc.getColor() == Node.BLACK &&
sRc.getColor() == Node.RED) {
sRc.setColor(Node.BLACK);
sibling.setColor(Node.RED);
rotateLeft(sibling);
}
}
deleteAdjust4(node);
}
private void deleteAdjust4(Node node) {
Node sibling = sibling(node);
Node parent = node.getParent();
sibling.setColor(parent.getColor());
parent.setColor(Node.BLACK);
if (node == parent.getLc()) {
sibling.getRc().setColor(Node.BLACK);
rotateLeft(parent);
} else {
sibling.getLc().setColor(Node.BLACK);
rotateRight(parent);
}
}
/**
* 第一种情况,根节点插入,置为黑色即可
*/
private void insertAdjust0(Node node) {
if (node.getParent() == null) {
node.setColor(Node.BLACK);
} else {
insertAdjust1(node);
}
}
/**
* 第二种情况,父节点为黑色,不用管
*/
private void insertAdjust1(Node node) {
if (node.getParent().getColor() == Node.BLACK) {
return;
} else {
insertAdjust2(node);
}
}
/**
* 第三种情况,父节点为红色,叔父节点为红色
*/
private void insertAdjust2(Node node) {
Node parent = node.getParent();
Node uncle = uncle(node);
Node grandparent = grandparent(node);
if (uncle != null && parent.getColor() == Node.RED &&
uncle.getColor() == Node.RED) {
parent.setColor(Node.BLACK);
uncle.setColor(Node.BLACK);
grandparent.setColor(Node.RED);
insertAdjust0(grandparent);
} else {
insertAdjust3(node);
}
}
/**
* 第四种情况,父节点为红色,叔父节点为黑色或为空
*/
private void insertAdjust3(Node node) {
Node parent = node.getParent();
Node grandparent = grandparent(node);
// 父节点是祖父节点的左孩子,节点是父节点的右孩子
if (node == parent.getRc() && parent == grandparent.getLc()) {
rotateLeft(parent);
node = node.getLc();
}
// 父节点是祖父节点的右孩子,节点是父节点的左孩子
else if (node == parent.getLc() && parent == grandparent.getRc()) {
rotateRight(parent);
node = node.getRc();
}
insertAdjust4(node);
}
/**
* 第五种情况,节点父亲为红色,叔父为黑色或为空
*/
private void insertAdjust4(Node node) {
Node parent = node.getParent();
Node grandparent = grandparent(node);
parent.setColor(Node.BLACK);
grandparent.setColor(Node.RED);
// 父节点是祖父节点的左孩子,节点是父节点的左孩子
if (node == parent.getLc() && parent == grandparent.getLc()) {
rotateRight(grandparent);
}
// 父节点是祖父节点的右孩子,节点是父节点的右孩子
else {
rotateLeft(grandparent);
}
}
/**
* 左旋
*/
private void rotateLeft(Node node) {
Node parent = node.getParent();
Node rc = node.getRc();
if (node == parent.getLc()) {
parent.setLc(rc);
} else {
parent.setRc(rc);
}
rc.setParent(parent);
Node rcLc = rc.getLc();
node.setRc(rcLc);
if (rcLc != Node.LEAF_NODE) {
rcLc.setParent(node);
}
rc.setLc(node);
node.setParent(rc);
}
/**
* 右旋
*/
private void rotateRight(Node node) {
Node parent = node.getParent();
Node lc = parent.getLc();
if (node == parent.getLc()) {
parent.setLc(lc);
} else {
parent.setRc(lc);
}
lc.setParent(parent);
Node lcRc = lc.getRc();
node.setLc(lcRc);
if (lcRc != Node.LEAF_NODE) {
lcRc.setParent(node);
}
lc.setRc(node);
node.setParent(lc);
}
/**
* 二叉搜索树插入方法
*/
private Node executeInsert(int data) {
if (root == null) {
root = new Node(data , Node.BLACK , null);
root.setLc(Node.LEAF_NODE);
root.setRc(Node.LEAF_NODE);
return root;
}
Node cur = root;
return doInsert(data , cur);
}
private Node doInsert(int data, Node cur) {
Node node = new Node(data , cur);
if (data <= cur.getData()) {
Node lc = cur.getLc();
if (lc != Node.LEAF_NODE) {
return doInsert(data , lc);
} else {
cur.setLc(node);
node.setLc(Node.LEAF_NODE);
node.setRc(Node.LEAF_NODE);
}
} else {
Node rc = cur.getRc();
if (rc != Node.LEAF_NODE) {
return doInsert(data , rc);
} else {
cur.setRc(node);
node.setLc(Node.LEAF_NODE);
node.setRc(Node.LEAF_NODE);
}
}
return node;
}
public static void main(String[] args) {
RedBlackTree redBlackTree = new RedBlackTree();
redBlackTree.insert(13);
redBlackTree.insert(8);
redBlackTree.insert(17);
redBlackTree.insert(1);
redBlackTree.insert(11);
redBlackTree.insert(15);
redBlackTree.insert(25);
redBlackTree.insert(6);
redBlackTree.insert(22);
redBlackTree.insert(27);
redBlackTree.delete(13 , redBlackTree.root);
System.out.println();
}
}