紅黑樹五個性質(可以參考維基百科)
- 節點是紅色或者黑色
- 根節點是黑色
- 葉子節點顏色爲黑色(不是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();
}
}