二叉樹與紅黑樹的java實現
阿新 • • 發佈:2018-10-31
二叉樹的java實現
public class BinaryTree {
/**
* 根節點
*/
private static Node root;
static class Node {
int key;
Node left, right, parent;
public Node(int key) {
this.key = key;
}
}
public BinaryTree(int key) {
root = new Node(key);
}
/**
* 中序遍歷
*
* @param node 根節點
*/
public void inOrderTreeWalk(Node node) {
if (node != null) {
inOrderTreeWalk(node.left);
System.out.print(node.key + ",");
inOrderTreeWalk(node.right);
}
}
/**
* 查詢
*
* @param node 根節點
* @param key 查詢值
* @return
*/
public Node treeSearch(Node node, int key) {
while (node != null && key != node.key) {
if (key < node.key) {
node = node.left;
} else {
node = node.right;
}
}
return node;
}
/**
* 最小值
*
* @param node 根節點
* @return
*/
public Node treeMinimum(Node node) {
while (node.left != null) {
node = node.left;
}
return node;
}
/**
* 最大值
*
* @param node 根節點
* @return
*/
public Node treeMaximum(Node node) {
while (node.right != null) {
node = node.right;
}
return node;
}
/**
* 前驅
*
* @param node 根節點
* @return
*/
public Node treePredecessor(Node node) {
// 如果存在左子樹,返回左子樹的最大值
if (node.left != null) {
return treeMaximum(node.left);
}
Node y = node.parent;
// 當不存在左子樹時,返回最低祖先節點
while (y != null && node == y.left) {
node = y;
y = y.parent;
}
return y;
}
/**
* 後繼
*
* @param node 根節點
* @return
*/
public Node treeSuccessor(Node node) {
// 如果存在右子樹,返回右子樹的最小值
if (node.right != null) {
return treeMinimum(node.right);
}
Node y = node.parent;
// 當不存在右子樹時,返回最低祖先節點
while (y != null && node == y.right) {
node = y;
y = y.parent;
}
return y;
}
/**
* 插入
*
* @param key 插入節點的關鍵值
*/
public void treeInsert(int key) {
// 建立插入節點
Node node = new Node(key);
// 定義插入節點的父節點變數
Node y = null;
// 定義臨時變數存根節點
Node x = root;
// 在根節點的左、右子樹中查詢插入位置
while (x != null) {
y = x;
if (key < x.key) {
x = x.left;
} else {
x = x.right;
}
}
node.parent = y;
if (y == null) {
root = node;
} else if (key < y.key) {
y.left = node;
} else {
y.right = node;
}
}
/**
* 刪除
*
* @param node 刪除節點
* @return
*/
public Node treeDelete(Node node) {
// 定義臨時變數存刪除節點或後繼節點
Node y;
// 當刪除節點至多有一個孩子時
if (node.left == null || node.right == null) {
y = node;
} else {// 當刪除節點有兩個孩子時,y存後繼節點
y = treeSuccessor(node);
}
// 定義臨時變數存刪除節點的孩子節點
Node x;
if (y.left != null) {
x = y.left;
} else {
x = y.right;
}
if (x != null) {
x.parent = y.parent;
}
if (y.parent == null) {
root = x;
} else if (y == y.parent.left) {
y.parent.left = x;
} else {
y.parent.right = x;
}
// 當y為後繼節點時,將y的關鍵值賦給刪除節點
if (y != node) {
node.key = y.key;
}
return y;
}
}
紅黑樹的java實現(備註:中序遍歷、查詢、最大、最小、前驅、後繼與二叉樹基本一致)
public class RBTree {
/**
* 根節點
*/
private static Node root;
/**
* nil節點是紅黑樹的葉子節點不同於二叉樹的葉子節點
* 顏色為黑色,key、left、right、parent可以是任意允許的值
* 這裡key設定為0,left、right、parent為null
*/
private Node nil = new Node(true);
static class Node {
int key;
Node left, right, parent;
boolean color;// true黑,false紅
public Node(int key) {
this.key = key;
}
public Node(boolean color) {
this.color = color;
}
public boolean equals(Node node) {
return this.key == node.key;
}
}
public RBTree(int key) {
root = new Node(key);
}
/**
* 中序遍歷
*
* @param node 根節點
*/
public void inOrderTreeWalk(Node node) {
if (node != null && !node.equals(nil)) {
inOrderTreeWalk(node.left);
System.out.print((node.color == true ? "黑" : "紅") + node.key + ",");
inOrderTreeWalk(node.right);
}
}
/**
* 查詢
*
* @param node 根節點
* @param key 查詢值
* @return
*/
public Node treeSearch(Node node, int key) {
while (node != null && key != node.key) {
if (key < node.key) {
node = node.left;
} else {
node = node.right;
}
}
return node;
}
/**
* 最小值
*
* @param node 根節點
* @return
*/
public Node treeMinimum(Node node) {
while (node.left != null) {
node = node.left;
}
return node;
}
/**
* 最大值
*
* @param node 根節點
* @return
*/
public Node treeMaximum(Node node) {
while (node.right != null) {
node = node.right;
}
return node;
}
/**
* 前驅
*
* @param node 根節點
* @return
*/
public Node treePredecessor(Node node) {
// 如果存在左子樹,返回左子樹的最大值
if (node.left != null) {
return treeMaximum(node.left);
}
Node y = node.parent;
// 當不存在左子樹時,返回最低祖先節點
while (y != null && node == y.left) {
node = y;
y = y.parent;
}
return y;
}
/**
* 後繼
*
* @param node 根節點
* @return
*/
public Node treeSuccessor(Node node) {
// 如果存在右子樹,返回右子樹的最小值
if (node.right != null) {
return treeMinimum(node.right);
}
Node y = node.parent;
// 當不存在右子樹時,返回最低祖先節點
while (y != null && node == y.right) {
node = y;
y = y.parent;
}
return y;
}
/**
* 左旋(node節點必有右孩子)
*
* @param node
*/
public void leftTotate(Node node) {
Node y = node.right;
node.right = y.left;
if (y.left != null)
y.left.parent = node;
y.parent = node.parent;
if (node.parent == null) {
root = y;
} else if (node == node.parent.left) {
node.parent.left = y;
} else {
node.parent.right = y;
}
node.parent = y;
y.left = node;
}
/**
* 右旋(node節點必有左孩子)
*
* @param node
*/
public void rightTotate(Node node) {
Node y = node.left;
node.left = y.right;
if (y.right != null)
y.right.parent = node;
y.parent = node.parent;
if (node.parent == null) {
root = y;
} else if (node == node.parent.left) {
node.parent.left = y;
} else {
node.parent.right = y;
}
node.parent = y;
y.right = node;
}
/**
* 插入
*
* @param key 插入節點的關鍵值
*/
public void RBTreeInsert(int key) {
// 建立插入節點
Node node = new Node(key);
// 定義插入節點的父節點變數
Node y = null;
// 定義臨時變數存根節點
Node x = root;
// 在根節點的左、右子樹中查詢插入位置
while (x != null) {
y = x;
if (key < x.key) {
x = x.left;
} else {
x = x.right;
}
}
node.parent = y;
if (y == null) {
root = node;
} else if (key < y.key) {
y.left = node;
} else {
y.right = node;
}
RBTreeInsertFixup(node);
}
/**
* 插入後修復
*
* @param node 插入節點
*/
public void RBTreeInsertFixup(Node node) {
// 當插入節點的父節點為紅色時,執行迴圈
while (node.parent != null && !node.parent.color && node.parent.parent != null) {
// 當插入節點的父節點為其爺爺節點的左孩子時
if (node.parent == node.parent.parent.left) {
// 定義y存叔叔節點
Node y = node.parent.parent.right;
// 如果叔叔節點為紅色,將父節點與叔叔節點變成黑色,爺爺節點變成紅色,將插入節點升級為爺爺節點
if (y != null && !y.color) {
node.parent.color = true;
y.color = true;
node.parent.parent.color = false;
node = node.parent.parent;
} else if (node == node.parent.right) {//如果叔叔節點為黑色,插入節點是父節點的右孩子,將插入節點升級為父節點,左旋插入節點
node = node.parent;
leftTotate(node);
} else {//如果叔叔節點為黑色,插入節點是父節點的左孩子,將父節點變成黑色,爺爺節點變成紅色,右旋爺爺節點
node.parent.color = true;
node.parent.parent.color = false;
rightTotate(node.parent.parent);
}
} else {// 當插入節點的父節點為其爺爺節點的右孩子時
// 定義y存叔叔節點
Node y = node.parent.parent.left;
// 如果叔叔節點為紅色,將父節點與叔叔節點變成黑色,爺爺節點變成紅色,將插入節點升級為爺爺節點
if (y != null && !y.color) {
node.parent.color = true;
y.color = true;
node.parent.parent.color = false;
node = node.parent.parent;
} else if (node == node.parent.left) {//如果叔叔節點為黑色,插入節點是父節點的左孩子,將插入節點升級為父節點,右旋插入節點
node = node.parent;
rightTotate(node);
} else {//如果叔叔節點為黑色,插入節點是父節點的右孩子,將父節點變成黑色,爺爺節點變成紅色,左旋爺爺節點
node.parent.color = true;
node.parent.parent.color = false;
leftTotate(node.parent.parent);
}
}
}
// 將根節點變成黑色
if (root.parent != null) {
root = root.parent;
}
root.color = true;
}
/**
* 刪除
*
* @param node 刪除節點
* @return
*/
public Node RBTreeDelete(Node node) {
// 定義臨時變數存刪除節點或後繼節點
Node y;
// 當刪除節點至多有一個孩子時
if (node.left == null || node.right == null) {
y = node;
} else {// 當刪除節點有兩個孩子時,y存後繼節點
y = treeSuccessor(node);
}
// 定義臨時變數存刪除節點的孩子節點
Node x;
if (y.left != null) {
x = y.left;
} else {
x = y.right;
}
if (x != null) {
x.parent = y.parent;
} else {
x = nil;
x.parent = y.parent;
}
if (y.parent == null) {
root = x;
} else if (y == y.parent.left) {
y.parent.left = x;
} else {
y.parent.right = x;
}
// 當y為後繼節點時,將y的關鍵值賦給刪除節點
if (y != node) {
node.key = y.key;
}
// 當y為黑色時,需要修復紅黑樹
if (y.color) {
RBTreeDeleteFixup(x);
}
return y;
}
/**
* 刪除後修復
*
* @param node 刪除節點的孩子節點
*/
public void RBTreeDeleteFixup(Node node) {
// 當node不等於根節點並且為黑色時,執行迴圈
while (node != root && (node == nil || node.color)) {
// 如果node節點為父節點的左孩子
if (node == node.parent.left) {
// 定義w存兄弟節點
Node w = node.parent.right;
// 當兄弟節點為紅色時,將兄弟節點變成黑色,父節點變成紅色,左旋父節點,更新兄弟節點
if (!w.color) {
w.color = true;
node.parent.color = false;
leftTotate(node.parent);
w = node.parent.right;
} else if (w.left.color && w.right.color) {//當兄弟節點為黑色且其兩個孩子都為黑色時,將兄弟節點變成紅色,將node節點升級為父節點
w.color = false;
node = node.parent;
} else if (w.right.color) {//當兄弟節點為黑色且其左孩子為紅色、其右孩子為黑色時,將其左孩子變成黑色、兄弟節點變成紅色,右旋兄弟節點,更新兄弟節點
w.left.color = true;
w.color = false;
rightTotate(w);
w = node.parent.right;
} else {//當兄弟節點為黑色且其右孩子為紅色時,將父節點的顏色賦給兄弟節點,父節點變成黑色,兄弟節點的右孩子變成黑色,左旋父節點
w.color = node.parent.color;
node.parent.color = true;
w.right.color = true;
leftTotate(node.parent);
// 將根節點賦給node
if (root.parent != null) {
root = root.parent;
}
node = root;
}
} else {// 如果node節點為父節點的右孩子
// 定義w存兄弟節點
Node w = node.parent.left;
// 當兄弟節點為紅色時,將兄弟節點變成黑色,父節點變成紅色,右旋父節點,更新兄弟節點
if (!w.color) {
w.color = true;
node.parent.color = false;
rightTotate(node.parent);
w = node.parent.left;
} else if (w.left.color && w.right.color) {//當兄弟節點為黑色且其兩個孩子都為黑色時,將兄弟節點變成紅色,將node節點升級為父節點
w.color = false;
node = node.parent;
} else if (w.left.color) {//當兄弟節點為黑色且其左孩子為黑色、其右孩子為紅色時,將其右孩子變成黑色、兄弟節點變成紅色,左旋兄弟節點,更新兄弟節點
w.right.color = true;
w.color = false;
leftTotate(w);
w = node.parent.left;
} else {//當兄弟節點為黑色且其左孩子為紅色時,將父節點的顏色賦給兄弟節點,父節點變成黑色,兄弟節點的左孩子變成黑色,右旋父節點
w.color = node.parent.color;
node.parent.color = true;
w.left.color = true;
rightTotate(node.parent);
// 將根節點賦給node
if (root.parent != null) {
root = root.parent;
}
node = root;
}
}
}
// 將node節點變成黑色
node.color = true;
}
public static void main(String[] args) {
int[] arr = { 21, 3, 6, 7, 12, 25, 17, 8, 15 };
RBTree rb = new RBTree(21);
for (int i = 1; i < arr.length; i++) {
rb.RBTreeInsert(arr[i]);
}
rb.inOrderTreeWalk(root);
rb.RBTreeDelete(rb.treeSearch(root, 21));
System.out.println();
rb.inOrderTreeWalk(root);
}
}