背景:自學紅黑樹
開發語言:JAVA
本片內容:用java實現紅黑樹的刪除php
紅黑樹是在1972年由Rudolf Bayer發明的,當時被稱爲平衡二叉B樹(symmetric binary B-trees)。後來,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改成現在的「紅黑樹」。
紅黑樹是一種特化的AVL樹(平衡二叉樹),都是在進行插入和刪除操做時經過特定操做保持二叉查找樹的平衡,從而得到較高的查找性能。
它雖然是複雜的,但它的最壞狀況運行時間也是很是良好的,而且在實踐中是高效的: 它能夠在O(log n)時間內作查找,插入和刪除,這裏的n 是樹中元素的數目。java
增長和刪除,紅黑樹效率高;查詢,AVL樹效率高app
一、每一個節點的顏色是紅色或者黑色
二、根節點是黑色
三、空葉子節點是黑色
四、紅色節點的子節點必定是黑色
五、從任意節點開始到葉子節點結束,所通過的黑色節點個數必定是相同的性能
package com.blueice.hello.BRTree;
/**
* @FileName: BRNode
* @Description: TODO(紅黑樹節點)
* @Author: shaoz
* @Date: 2021/7/8 10:43
* @Copyright: 2021 www.***.com.cn All rights reserved.
* 注意:本內容僅限於***內部傳閱,禁止外泄以及用於其餘的商業目的
*/
public class BRNode {
BRNode parent;
TreeColor treeColor;
BRNode left;
BRNode right;
int value;
public BRNode(int value) {
this.value = value;
this.parent = null;
this.left = null;
this.right = null;
this.treeColor = TreeColor.RED;
}
}
package com.blueice.hello.BRTree;
/**
* @FileName: TreeColor
* @Description: TODO(紅黑樹的顏色)
* @Author: shaoz
* @Date: 2021/7/8 15:23
* @Copyright: 2021 www.***.com.cn All rights reserved.
* 注意:本內容僅限於***內部傳閱,禁止外泄以及用於其餘的商業目的
*/
public enum TreeColor {
/**
* 紅黑樹的顏色
*/
BLACK("黑色"),RED("紅色");
private String color;
TreeColor(String color) {
this.color = color;
}
public String getColor() {
return color;
}
}
package com.blueice.hello.BRTree;
/**
* @FileName: BRTree
* @Description: TODO(紅黑樹)
* @Author: shaoz
* @Date: 2021/7/8 11:14
* @Copyright: 2021 www.***.com.cn All rights reserved.
* 注意:本內容僅限於***內部傳閱,禁止外泄以及用於其餘的商業目的
*/
public class BRTree {
BRNode root;
public BRTree(int value) {
this.root = new BRNode(value);
this.root.treeColor = TreeColor.BLACK;
}
/**
* 刪除紅黑樹中的值
* @param value 要刪除的值
*/
public void remove(int value) {
BRNode curNode = root;
while (curNode != null) {
if (value == curNode.value) {
removeNode(curNode);
break;
} else if (value > curNode.value) {
curNode = curNode.right;
} else {
curNode = curNode.left;
}
}
}
/**
* 刪除節點
* @param curNode 要刪除的節點
*/
private void removeNode(BRNode curNode) {
/* 刪除節點後的替換節點 */
BRNode replaceNode = null;
/* 有2個子節點:找到後繼節點,繼續遞歸(只會遞歸一次,由於後繼節點確定沒有兩個非空子節點) */
if (null != curNode.left && null != curNode.right) {
for (replaceNode = curNode.right; null != replaceNode.left; replaceNode = replaceNode.left){};
curNode.value = replaceNode.value;
removeNode(replaceNode);
/* 沒有子節點 */
} else if (null == curNode.left && null == curNode.right) {
/* 當前節點是根節點,直接把紅黑樹置空 */
if (null == curNode.parent) {
this.root = null;
return;
}
/* 當前節點顏色爲紅色:直接刪除 */
if (TreeColor.RED == curNode.treeColor) {
if (curNode == curNode.parent.left) {
curNode.parent.left = null;
} else {
curNode.parent.right = null;
}
/* 當前節點爲黑色,進行刪除平衡操做 */
} else {
/* 刪掉當前節點 */
BRNode parNode = curNode.parent;
BRNode broNode;
if (curNode == parNode.left) {
parNode.left = null;
broNode = parNode.right;
} else {
parNode.right = null;
broNode = parNode.left;
}
/* 進行刪除平衡操做 */
removeFixUp(parNode, broNode);
}
/* 有1個子節點:必定是黑-紅,刪掉當前節點,把紅色子節點放到當前位置,並染爲黑色 */
} else {
BRNode curParent = curNode.parent;
BRNode sonNode;
if (null != curNode.left) {
sonNode = curNode.left;
} else {
sonNode = curNode.right;
}
sonNode.parent = curParent;
if (null != curParent) {
if (curNode == curParent.left) {
curParent.left = sonNode;
} else {
curParent.right = sonNode;
}
} else {
sonNode.treeColor = TreeColor.BLACK;
this.root = sonNode;
}
sonNode.treeColor = TreeColor.BLACK;
}
}
/**
* 紅黑樹刪除平衡操做(被刪除節點爲黑色,而且子節點全爲NIL)
* @param parNode 父節點
* @param broNode 兄弟節點
*/
private void removeFixUp(BRNode parNode, BRNode broNode) {
/* <1> 當前節點爲根節點
// <2> 兄弟節點是黑色
// [1] 兄子節點全爲NIL(全黑)
// {1} 父紅
// {2} 父黑
// [2] 兄子節點不全黑
// {1} 兄在左,兄左子節點紅色
// {2} 兄在右,兄右子節點紅色
// {3} 兄在左,兄左子節點黑色
// {4} 兄在右,兄右子節點黑色
// <3> 兄弟節點是紅色
// [1] 兄在左
// [2] 兄在右 */
/* <1>當前節點是根節點 */
if (null == parNode) {
return;
/* <2>兄弟節點是黑色 */
} else if (TreeColor.BLACK == broNode.treeColor) {
/* <2.1>兄弟節點的子節點全爲NIL或者全爲黑色 */
if ((null == broNode.left && null == broNode.right)
|| (broNode.left != null && TreeColor.BLACK ==broNode.left.treeColor && broNode.right != null && TreeColor.BLACK ==broNode.right.treeColor)) {
/* <2.1.1>父節點是紅色節點 */
if (TreeColor.RED == parNode.treeColor) {
/* 交換父親節點與兄弟節點顏色,平衡結束。 */
broNode.treeColor = TreeColor.RED;
parNode.treeColor = TreeColor.BLACK;
/* <2.1.2>父節點是黑色節點 */
} else {
/* 把兄弟節點塗紅 */
broNode.treeColor = TreeColor.RED;
/* 把父節點做爲平衡節點繼續遞歸處理 */
BRNode tempParNode = parNode;
parNode = parNode.parent;
broNode = parNode==tempParNode.left ? tempParNode.right : tempParNode.left;
removeFixUp(parNode, broNode);
}
/* <2.2>兄弟節點的子節點不全爲黑色節點 */
} else {
/* <2.2.1>(1)兄弟節點爲左子節點,兄弟節點的左子節點爲紅色
if (broNode == parNode.left && null != broNode.left && TreeColor.RED == broNode.left.treeColor) {
/* 以P爲支點右旋;交換P和B顏色,BL塗黑;平衡結束。 */
TreeColor curColor = parNode.treeColor;
parNode.treeColor = broNode.treeColor;
broNode.treeColor = curColor;
broNode.left.treeColor = TreeColor.BLACK;
rightHand(parNode, broNode);
/* <2.2.1>(2)兄弟節點爲右子節點,兄弟節點的右子節點爲紅色 */
} else if(broNode == parNode.right && null != broNode.right && TreeColor.RED == broNode.right.treeColor) {
/* 以P爲支點左旋,交換P和B顏色,BR塗黑,平衡結束。 */
TreeColor curColor = parNode.treeColor;
parNode.treeColor = broNode.treeColor;
broNode.treeColor = curColor;
broNode.right.treeColor = TreeColor.BLACK;
leftHand(parNode, broNode);
/* <2.2.2>(1)兄弟節點爲左子節點,兄弟節點的左子節點爲黑色 */
} else if (broNode == parNode.left && null != broNode.left && TreeColor.BLACK == broNode.left.treeColor) {
/* 以B爲支點左旋,交換B和BR顏色 */
TreeColor broColor = broNode.treeColor;
broNode.treeColor = broNode.right.treeColor;
broNode.right.treeColor = broColor;
leftHand(broNode, broNode.right);
/* 轉至2.2.1-(1) */
removeFixUp(parNode, broNode.right);
/* <2.2.2>(2)兄弟節點爲右子節點,兄弟節點的右子節點爲黑色 */
} else if (broNode == parNode.right && null != broNode.right && TreeColor.BLACK == broNode.right.treeColor) {
/* 以B爲支點右旋,交換B和BL顏色 */
TreeColor broColor = broNode.treeColor;
broNode.treeColor = broNode.left.treeColor;
broNode.left.treeColor = broColor;
rightHand(broNode, broNode.left);
/* 轉至2.2.1-(2) */
removeFixUp(parNode, broNode.left);
}
}
/* <3>兄弟節點爲紅色 */
} else if (TreeColor.RED == broNode.treeColor) {
/* <3.1>兄弟節點爲左子節點 */
if (broNode == parNode.left) {
/* 以P爲支點右旋,交換P和B顏色,轉向情形<2>兄黑 */
TreeColor broColor = parNode.treeColor;
parNode.treeColor = broNode.treeColor;
broNode.treeColor = broColor;
rightHand(parNode, broNode);
removeFixUp(parNode, broNode.right);
/* <3.2>兄弟節點爲右子節點 */
} else if (broNode == parNode.right) {
/* 以P爲支點左旋,交換P和B顏色,轉向情形<2>兄黑 */
TreeColor broColor = parNode.treeColor;
parNode.treeColor = broNode.treeColor;
broNode.treeColor = broColor;
leftHand(parNode, broNode);
removeFixUp(parNode, broNode.left);
}
}
}
/**
* 左旋
* @param parent 父節點
* @param current 中間節點
*/
private void leftHand(BRNode parent, BRNode current) {
BRNode grandPa = parent.parent;
if (grandPa != null) {
if (grandPa.left == parent) {
grandPa.left = current;
} else {
grandPa.right = current;
}
}
parent.parent = current;
parent.right = current.left;
current.left.parent = parent;
current.parent = grandPa;
current.left = parent;
}
/**
* 右旋
* @param parent 父節點
* @param current 中間節點
*/
private void rightHand(BRNode parent, BRNode current) {
BRNode grandPa = parent.parent;
if (grandPa != null) {
if (grandPa.left == parent) {
grandPa.left = current;
} else {
grandPa.right = current;
}
}
parent.parent = current;
parent.left = current.right;
current.right.parent = parent;
current.parent = grandPa;
current.right = parent;
}
}
圖例還在寫,添加的代碼下次上傳,由於是先學的添加,後學的刪除,如今添加方法已經模糊了。。。ui