一、源碼:java
package demo20; /** * @description implementation of Red-Black Tree by Java * @author eson_15 * @param <T> * @date 2016-4-18 19:27:28 */ public class RBTree<T extends Comparable<T>> { private RBNode<T> root; //根節點 private static final boolean RED = false; //定義紅黑樹標誌 private static final boolean BLACK = true; //內部類:節點類 public class RBNode<T extends Comparable<T>>{ boolean color; //顏色 T key; //關鍵字(鍵值) RBNode<T> left; //左子節點 RBNode<T> right; //右子節點 RBNode<T> parent; //父節點 public RBNode(T key, boolean color, RBNode<T> parent, RBNode<T> left, RBNode<T> right) { this.key = key; this.color = color; this.parent = parent; this.left = left; this.right = right; } public T getKey() { return key; } public String toString() { return "" + key + (this.color == RED? "R" : "B"); } } public RBTree() { root = null; } public RBNode<T> parentOf(RBNode<T> node) { //得到父節點 return node != null? node.parent : null; } public void setParent(RBNode<T> node, RBNode<T> parent) { //設置父節點 if(node != null) node.parent = parent; } public boolean colorOf(RBNode<T> node) { //得到節點的顏色 return node != null? node.color : BLACK; } public boolean isRed(RBNode<T> node) { //判斷節點的顏色 return (node != null)&&(node.color == RED)? true : false; } public boolean isBlack(RBNode<T> node) { return !isRed(node); } public void setRed(RBNode<T> node) { //設置節點的顏色 if(node != null) node.color = RED; } public void setBlack(RBNode<T> node) { if(node != null) { node.color = BLACK; } } public void setColor(RBNode<T> node, boolean color) { if(node != null) node.color = color; } /***************** 前序遍歷紅黑樹 *********************/ public void preOrder() { preOrder(root); } private void preOrder(RBNode<T> tree) { if(tree != null) { System.out.print(tree.key + " "); preOrder(tree.left); preOrder(tree.right); } } /***************** 中序遍歷紅黑樹 *********************/ public void inOrder() { inOrder(root); } private void inOrder(RBNode<T> tree) { if(tree != null) { preOrder(tree.left); System.out.print(tree.key + " "); preOrder(tree.right); } } /***************** 後序遍歷紅黑樹 *********************/ public void postOrder() { postOrder(root); } private void postOrder(RBNode<T> tree) { if(tree != null) { preOrder(tree.left); preOrder(tree.right); System.out.print(tree.key + " "); } } /**************** 查找紅黑樹中鍵值爲key的節點 ***************/ public RBNode<T> search(T key) { return search(root, key); // return search2(root, key); //使用遞歸的方法,本質同樣的 } private RBNode<T> search(RBNode<T> x, T key) { while(x != null) { int cmp = key.compareTo(x.key); if(cmp < 0) x = x.left; else if(cmp > 0) x = x.right; else return x; } return x; } //使用遞歸 private RBNode<T> search2(RBNode<T> x, T key) { if(x == null) return x; int cmp = key.compareTo(x.key); if(cmp < 0) return search2(x.left, key); else if(cmp > 0) return search2(x.right, key); else return x; } /**************** 查找最小節點的值 **********************/ public T minValue() { RBNode<T> node = minNode(root); if(node != null) return node.key; return null; } private RBNode<T> minNode(RBNode<T> tree) { if(tree == null) return null; while(tree.left != null) { tree = tree.left; } return tree; } /******************** 查找最大節點的值 *******************/ public T maxValue() { RBNode<T> node = maxNode(root); if(node != null) return node.key; return null; } private RBNode<T> maxNode(RBNode<T> tree) { if(tree == null) return null; while(tree.right != null) tree = tree.right; return tree; } /********* 查找節點x的後繼節點,即大於節點x的最小節點 ***********/ public RBNode<T> successor(RBNode<T> x) { //若是x有右子節點,那麼後繼節點爲「以右子節點爲根的子樹的最小節點」 if(x.right != null) return minNode(x.right); //若是x沒有右子節點,會出現如下兩種狀況: //1. x是其父節點的左子節點,則x的後繼節點爲它的父節點 //2. x是其父節點的右子節點,則先查找x的父節點p,而後對p再次進行這兩個條件的判斷 RBNode<T> p = x.parent; while((p != null) && (x == p.right)) { //對應狀況2 x = p; p = x.parent; } return p; //對應狀況1 } /********* 查找節點x的前驅節點,即小於節點x的最大節點 ************/ public RBNode<T> predecessor(RBNode<T> x) { //若是x有左子節點,那麼前驅結點爲「左子節點爲根的子樹的最大節點」 if(x.left != null) return maxNode(x.left); //若是x沒有左子節點,會出現如下兩種狀況: //1. x是其父節點的右子節點,則x的前驅節點是它的父節點 //2. x是其父節點的左子節點,則先查找x的父節點p,而後對p再次進行這兩個條件的判斷 RBNode<T> p = x.parent; while((p != null) && (x == p.left)) { //對應狀況2 x = p; p = x.parent; } return p; //對應狀況1 } /*************對紅黑樹節點x進行左旋操做 ******************/ /* * 左旋示意圖:對節點x進行左旋 * p p * / / * x y * / \ / \ * lx y -----> x ry * / \ / \ * ly ry lx ly * 左旋作了三件事: * 1. 將y的左子節點賦給x的右子節點,並將x賦給y左子節點的父節點(y左子節點非空時) * 2. 將x的父節點p(非空時)賦給y的父節點,同時更新p的子節點爲y(左或右) * 3. 將y的左子節點設爲x,將x的父節點設爲y */ private void leftRotate(RBNode<T> x) { //1. 將y的左子節點賦給x的右子節點,並將x賦給y左子節點的父節點(y左子節點非空時) RBNode<T> y = x.right; x.right = y.left; if(y.left != null) y.left.parent = x; //2. 將x的父節點p(非空時)賦給y的父節點,同時更新p的子節點爲y(左或右) y.parent = x.parent; if(x.parent == null) { this.root = y; //若是x的父節點爲空,則將y設爲父節點 } else { if(x == x.parent.left) //若是x是左子節點 x.parent.left = y; //則也將y設爲左子節點 else x.parent.right = y;//不然將y設爲右子節點 } //3. 將y的左子節點設爲x,將x的父節點設爲y y.left = x; x.parent = y; } /*************對紅黑樹節點y進行右旋操做 ******************/ /* * 左旋示意圖:對節點y進行右旋 * p p * / / * y x * / \ / \ * x ry -----> lx y * / \ / \ * lx rx rx ry * 右旋作了三件事: * 1. 將x的右子節點賦給y的左子節點,並將y賦給x右子節點的父節點(x右子節點非空時) * 2. 將y的父節點p(非空時)賦給x的父節點,同時更新p的子節點爲x(左或右) * 3. 將x的右子節點設爲y,將y的父節點設爲x */ private void rightRotate(RBNode<T> y) { //1. 將y的左子節點賦給x的右子節點,並將x賦給y左子節點的父節點(y左子節點非空時) RBNode<T> x = y.left; y.left = x.right; if(x.right != null) x.right.parent = y; //2. 將x的父節點p(非空時)賦給y的父節點,同時更新p的子節點爲y(左或右) x.parent = y.parent; if(y.parent == null) { this.root = x; //若是x的父節點爲空,則將y設爲父節點 } else { if(y == y.parent.right) //若是x是左子節點 y.parent.right = x; //則也將y設爲左子節點 else y.parent.left = x;//不然將y設爲右子節點 } //3. 將y的左子節點設爲x,將x的父節點設爲y x.right = y; y.parent = x; } /*********************** 向紅黑樹中插入節點 **********************/ public void insert(T key) { RBNode<T> node = new RBNode<T>(key, RED, null, null, null); if(node != null) insert(node); } //將節點插入到紅黑樹中,這個過程與二叉搜索樹是同樣的 private void insert(RBNode<T> node) { RBNode<T> current = null; //表示最後node的父節點 RBNode<T> x = this.root; //用來向下搜索用的 //1. 找到插入的位置 while(x != null) { current = x; int cmp = node.key.compareTo(x.key); if(cmp < 0) x = x.left; else x = x.right; } node.parent = current; //找到了位置,將當前current做爲node的父節點 //2. 接下來判斷node是插在左子節點仍是右子節點 if(current != null) { int cmp = node.key.compareTo(current.key); if(cmp < 0) current.left = node; else current.right = node; } else { this.root = node; } //3. 將它從新修整爲一顆紅黑樹 insertFixUp(node); } private void insertFixUp(RBNode<T> node) { RBNode<T> parent, gparent; //定義父節點和祖父節點 //須要修整的條件:父節點存在,且父節點的顏色是紅色 while(((parent = parentOf(node)) != null) && isRed(parent)) { gparent = parentOf(parent);//得到祖父節點 //若父節點是祖父節點的左子節點,下面else與其相反 if(parent == gparent.left) { RBNode<T> uncle = gparent.right; //得到叔叔節點 //case1: 叔叔節點也是紅色 if(uncle != null && isRed(uncle)) { setBlack(parent); //把父節點和叔叔節點塗黑 setBlack(uncle); setRed(gparent); //把祖父節點塗紅 node = gparent; //將位置放到祖父節點處 continue; //繼續while,從新判斷 } //case2: 叔叔節點是黑色,且當前節點是右子節點 if(node == parent.right) { leftRotate(parent); //從父節點處左旋 RBNode<T> tmp = parent; //而後將父節點和本身調換一下,爲下面右旋作準備 parent = node; node = tmp; } //case3: 叔叔節點是黑色,且當前節點是左子節點 setBlack(parent); setRed(gparent); rightRotate(gparent); } else { //若父節點是祖父節點的右子節點,與上面的徹底相反,本質同樣的 RBNode<T> uncle = gparent.left; //case1: 叔叔節點也是紅色 if(uncle != null & isRed(uncle)) { setBlack(parent); setBlack(uncle); setRed(gparent); node = gparent; continue; } //case2: 叔叔節點是黑色的,且當前節點是左子節點 if(node == parent.left) { rightRotate(parent); RBNode<T> tmp = parent; parent = node; node = tmp; } //case3: 叔叔節點是黑色的,且當前節點是右子節點 setBlack(parent); setRed(gparent); leftRotate(gparent); } } //將根節點設置爲黑色 setBlack(this.root); } /*********************** 刪除紅黑樹中的節點 **********************/ public void remove(T key) { RBNode<T> node; if((node = search(root, key)) != null) remove(node); } private void remove(RBNode<T> node) { RBNode<T> child, parent; boolean color; //1. 被刪除的節點「左右子節點都不爲空」的狀況 if((node.left != null) && (node.right != null)) { //先找到被刪除節點的後繼節點,用它來取代被刪除節點的位置 RBNode<T> replace = node; // 1). 獲取後繼節點 replace = replace.right; while(replace.left != null) replace = replace.left; // 2). 處理「後繼節點」和「被刪除節點的父節點」之間的關係 if(parentOf(node) != null) { //要刪除的節點不是根節點 if(node == parentOf(node).left) parentOf(node).left = replace; else parentOf(node).right = replace; } else { //不然 this.root = replace; } // 3). 處理「後繼節點的子節點」和「被刪除節點的子節點」之間的關係 child = replace.right; //後繼節點確定不存在左子節點! parent = parentOf(replace); color = colorOf(replace);//保存後繼節點的顏色 if(parent == node) { //後繼節點是被刪除節點的子節點 parent = replace; } else { //不然 if(child != null) setParent(child, parent); parent.left = child; replace.right = node.right; setParent(node.right, replace); } replace.parent = node.parent; replace.color = node.color; //保持原來位置的顏色 replace.left = node.left; node.left.parent = replace; if(color == BLACK) { //4. 若是移走的後繼節點顏色是黑色,從新修整紅黑樹 removeFixUp(child, parent);//將後繼節點的child和parent傳進去 } node = null; return; } } //node表示待修正的節點,即後繼節點的子節點(由於後繼節點被挪到刪除節點的位置去了) private void removeFixUp(RBNode<T> node, RBNode<T> parent) { RBNode<T> other; while((node == null || isBlack(node)) && (node != this.root)) { if(parent.left == node) { //node是左子節點,下面else與這裏的恰好相反 other = parent.right; //node的兄弟節點 if(isRed(other)) { //case1: node的兄弟節點other是紅色的 setBlack(other); setRed(parent); leftRotate(parent); other = parent.right; } //case2: node的兄弟節點other是黑色的,且other的兩個子節點也都是黑色的 if((other.left == null || isBlack(other.left)) && (other.right == null || isBlack(other.right))) { setRed(other); node = parent; parent = parentOf(node); } else { //case3: node的兄弟節點other是黑色的,且other的左子節點是紅色,右子節點是黑色 if(other.right == null || isBlack(other.right)) { setBlack(other.left); setRed(other); rightRotate(other); other = parent.right; } //case4: node的兄弟節點other是黑色的,且other的右子節點是紅色,左子節點任意顏色 setColor(other, colorOf(parent)); setBlack(parent); setBlack(other.right); leftRotate(parent); node = this.root; break; } } else { //與上面的對稱 other = parent.left; if (isRed(other)) { // Case 1: node的兄弟other是紅色的 setBlack(other); setRed(parent); rightRotate(parent); other = parent.left; } if ((other.left==null || isBlack(other.left)) && (other.right==null || isBlack(other.right))) { // Case 2: node的兄弟other是黑色,且other的倆個子節點都是黑色的 setRed(other); node = parent; parent = parentOf(node); } else { if (other.left==null || isBlack(other.left)) { // Case 3: node的兄弟other是黑色的,而且other的左子節點是紅色,右子節點爲黑色。 setBlack(other.right); setRed(other); leftRotate(other); other = parent.left; } // Case 4: node的兄弟other是黑色的;而且other的左子節點是紅色的,右子節點任意顏色 setColor(other, colorOf(parent)); setBlack(parent); setBlack(other.left); rightRotate(parent); node = this.root; break; } } } if (node!=null) setBlack(node); } /****************** 銷燬紅黑樹 *********************/ public void clear() { destroy(root); root = null; } private void destroy(RBNode<T> tree) { if(tree == null) return; if(tree.left != null) destroy(tree.left); if(tree.right != null) destroy(tree.right); tree = null; } /******************* 打印紅黑樹 *********************/ public void print() { if(root != null) { print(root, root.key, 0); } } /* * key---節點的鍵值 * direction--- 0:表示該節點是根節點 * 1:表示該節點是它的父節點的左子節點 * 2:表示該節點是它的父節點的右子節點 */ private void print(RBNode<T> tree, T key, int direction) { if(tree != null) { if(0 == direction) System.out.printf("%2d(B) is root\n", tree.key); else System.out.printf("%2d(%s) is %2d's %6s child\n", tree.key, isRed(tree)?"R":"b", key, direction == 1?"right":"left"); print(tree.left, tree.key, -1); print(tree.right, tree.key, 1); } } }
二、測試node
package demo20; public class RBTreeTest { private static final int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80}; private static final boolean mDebugInsert = true; // "插入"動做的檢測開關(false,關閉;true,打開) private static final boolean mDebugDelete = true; // "刪除"動做的檢測開關(false,關閉;true,打開) public static void main(String[] args) { int i, ilen = a.length; RBTree<Integer> tree = new RBTree<Integer>(); System.out.printf("== 原始數據: "); for(i=0; i<ilen; i++) System.out.printf("%d ", a[i]); System.out.printf("\n"); for(i=0; i<ilen; i++) { tree.insert(a[i]); // 設置mDebugInsert=true,測試"添加函數" if (mDebugInsert) { System.out.printf("== 添加節點: %d\n", a[i]); System.out.printf("== 樹的詳細信息: \n"); tree.print(); System.out.printf("\n"); } } System.out.printf("== 前序遍歷: "); tree.preOrder(); System.out.printf("\n== 中序遍歷: "); tree.inOrder(); System.out.printf("\n== 後序遍歷: "); tree.postOrder(); System.out.printf("\n"); System.out.printf("== 最小值: %s\n", tree.minValue()); System.out.printf("== 最大值: %s\n", tree.maxValue()); System.out.printf("== 樹的詳細信息: \n"); tree.print(); System.out.printf("\n"); // 設置mDebugDelete=true,測試"刪除函數" if (mDebugDelete) { for(i=0; i<ilen; i++) { tree.remove(a[i]); System.out.printf("== 刪除節點: %d\n", a[i]); System.out.printf("== 樹的詳細信息: \n"); tree.print(); System.out.printf("\n"); } } } }
執行結果:函數
== 原始數據: 10 40 30 60 90 70 20 50 80 == 添加節點: 10 == 樹的詳細信息: 10(B) is root == 添加節點: 40 == 樹的詳細信息: 10(B) is root 40(R) is 10's right child == 添加節點: 30 == 樹的詳細信息: 30(B) is root 10(R) is 30's left child 40(R) is 30's right child == 添加節點: 60 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 40(b) is 30's right child 60(R) is 40's right child == 添加節點: 90 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 60(b) is 30's right child 40(R) is 60's left child 90(R) is 60's right child == 添加節點: 70 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 60(R) is 30's right child 40(b) is 60's left child 90(b) is 60's right child 70(R) is 90's left child == 添加節點: 20 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 20(R) is 10's right child 60(R) is 30's right child 40(b) is 60's left child 90(b) is 60's right child 70(R) is 90's left child == 添加節點: 50 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 20(R) is 10's right child 60(R) is 30's right child 40(b) is 60's left child 50(R) is 40's right child 90(b) is 60's right child 70(R) is 90's left child == 添加節點: 80 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 20(R) is 10's right child 60(R) is 30's right child 40(b) is 60's left child 50(R) is 40's right child 80(b) is 60's right child 70(R) is 80's left child 90(R) is 80's right child == 前序遍歷: 30 10 20 60 40 50 80 70 90 == 中序遍歷: 10 20 30 60 40 50 80 70 90 == 後序遍歷: 10 20 60 40 50 80 70 90 30 == 最小值: 10 == 最大值: 90 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 20(R) is 10's right child 60(R) is 30's right child 40(b) is 60's left child 50(R) is 40's right child 80(b) is 60's right child 70(R) is 80's left child 90(R) is 80's right child == 刪除節點: 10 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 20(R) is 10's right child 60(R) is 30's right child 40(b) is 60's left child 50(R) is 40's right child 80(b) is 60's right child 70(R) is 80's left child 90(R) is 80's right child == 刪除節點: 40 == 樹的詳細信息: 30(B) is root 10(b) is 30's left child 20(R) is 10's right child 60(R) is 30's right child 40(b) is 60's left child 50(R) is 40's right child 80(b) is 60's right child 70(R) is 80's left child 90(R) is 80's right child == 刪除節點: 30 == 樹的詳細信息: 40(B) is root 10(b) is 40's left child 20(R) is 10's right child 60(R) is 40's right child 50(b) is 60's left child 80(b) is 60's right child 70(R) is 80's left child 90(R) is 80's right child == 刪除節點: 60 == 樹的詳細信息: 40(B) is root 10(b) is 40's left child 20(R) is 10's right child 70(R) is 40's right child 50(b) is 70's left child 80(b) is 70's right child 90(R) is 80's right child == 刪除節點: 90 == 樹的詳細信息: 40(B) is root 10(b) is 40's left child 20(R) is 10's right child 70(R) is 40's right child 50(b) is 70's left child 80(b) is 70's right child 90(R) is 80's right child == 刪除節點: 70 == 樹的詳細信息: 40(B) is root 10(b) is 40's left child 20(R) is 10's right child 80(R) is 40's right child 50(b) is 80's left child 90(b) is 80's right child == 刪除節點: 20 == 樹的詳細信息: 40(B) is root 10(b) is 40's left child 20(R) is 10's right child 80(R) is 40's right child 50(b) is 80's left child 90(b) is 80's right child == 刪除節點: 50 == 樹的詳細信息: 40(B) is root 10(b) is 40's left child 20(R) is 10's right child 80(R) is 40's right child 50(b) is 80's left child 90(b) is 80's right child == 刪除節點: 80 == 樹的詳細信息: 40(B) is root 10(b) is 40's left child 20(R) is 10's right child 90(b) is 40's right child 50(R) is 90's left child