java 红黑树 实现类 及 测试类

xiaoxiao2025-04-16  7

package org.xlj; /** * red black tree * @param <K> key * @param <V> value */ public class RBTree<K, V> { Comparetor<K> comparetor; Node<K, V> root; public Comparetor<K> getComparetor() { return comparetor; } public void setComparetor(Comparetor<K> comparetor) { this.comparetor = comparetor; } public Node<K, V> getRoot() { return root; } public void setRoot(Node<K, V> root) { this.root = root; } /** * get node by key from this rb-tree * @param key * @return * @throws Exception */ public Node get(K key) throws Exception { if(this.getComparetor() == null) { throw new Exception("this comparetor of the tree is null."); } Node<K, V> current = this.getRoot(); while (current != null) { //in right if(this.getComparetor().compare(key, current.getKey()) > 0) { current = current.getRightChild(); } else if(this.getComparetor().compare(key, current.getKey()) < 0) //in left { current = current.getLeftChild(); } else // equals 0 { break; } } return current; } /** * insert * @param node */ public void insert(Node<K, V> node) throws Exception { if(this.comparetor == null) { throw new Exception("this comparetor of the tree is null."); } if(this.get(node.key) != null) { throw new Exception("has exists this key: " + node.getKey()); } if(this.getRoot() == null) { this.setRoot(node); } Node<K, V> currentNode = this.getRoot(); int nCompareResult = 0; while (currentNode != null) { nCompareResult = 0; nCompareResult = this.comparetor.compare(currentNode.getKey(), node.getKey()); if(nCompareResult > 0) { if(currentNode.getLeftChild() != null) { currentNode = currentNode.getLeftChild(); } else { currentNode.setLeftChild(node); node.setParent(currentNode); break; } } if(nCompareResult < 0) { if(currentNode.getRightChild() != null) { currentNode = currentNode.getRightChild(); } else { currentNode.setRightChild(node); node.setParent(currentNode); break; } } //has already exist if (nCompareResult == 0) { // break; throw new Exception("this ket is already exsist: " + node.getKey()); } } this.insertFixup(node); this.getRoot().setColor(Node.NodeColors.BLACK); } /** * insert fix of the tree * @param addedNode be inserted node */ private void insertFixup(Node addedNode) { //directly return if addedNode is root if(addedNode == this.getRoot() || addedNode.getParent().getColor() == Node.NodeColors.BLACK) { return; } while (addedNode.getParent() != null && addedNode.getParent().getParent() != null && addedNode.getParent().getColor() == Node.NodeColors.RED ) { //parent Node parent = addedNode.getParent(); //grandParent Node grandParent = parent.getParent(); //uncle Node uncle = grandParent == null ? null : grandParent.getLeftChild() == parent ? grandParent.getRightChild() : grandParent.getLeftChild(); // case 1: brother of parent and uncle color is red if (uncle != null && uncle.getColor() == Node.NodeColors.RED) { parent.setColor(Node.NodeColors.BLACK); uncle.setColor(Node.NodeColors.BLACK); grandParent.setColor(Node.NodeColors.RED); addedNode = grandParent; continue; } //parent is left of the grandparent if (parent == grandParent.getLeftChild()) { // case 2: black of the uncle color, addedNode is right node of the parent if (addedNode == parent.getRightChild()) { addedNode = parent; this.leftRotate(this, addedNode); //parent parent = addedNode.getParent(); if (parent == null) { break; } //parent of parent grandParent = parent.getParent(); } // case 3: black of the uncle color, addedNode is left node of the parent parent.setColor(Node.NodeColors.BLACK); if (grandParent == null) { break; } grandParent.setColor(Node.NodeColors.RED); this.rightRotate(this, grandParent); } else //parent == parent.right reverse { // case 2: if(addedNode == parent.getLeftChild()) { addedNode = parent; this.rightRotate(this, addedNode); //parent parent = addedNode.getParent(); if (parent == null) { break; } //parent of parent grandParent = parent.getParent(); } //case 3: parent.setColor(Node.NodeColors.BLACK); if(grandParent == null) { break; } grandParent.setColor(Node.NodeColors.RED); this.leftRotate(this, grandParent); } } } /** * remove a node from this tree and keep rb-tree's feature * @param key * @throws Exception */ public void remove(K key) throws Exception { Node node = this.get(key); if(node == null) { throw new Exception("does not find this key: " + key); } Object[] nodes = this.removeNode(node); // removed node color is black if((Node.NodeColors)nodes[2] == Node.NodeColors.BLACK && this.getRoot() != null) { this.removeFixup((Node) nodes[0], (Node)nodes[1]); } } /** * remove * @param node * @return x at index 1, x's parent at index 2, node origin color at 3 */ private Object[] removeNode(Node node) { Node.NodeColors originColor = node.color; //node's successor(y) Node successor = null; // x Node x = null; // if x == null, then have to use parentOfx Node parentOfx = null; //case 1: left child is null and right not null if(node.getLeftChild() == null && node.getRightChild() !=null) { successor = node.getRightChild(); x = successor; parentOfx = node.parent; } //case 2: right child is null and left not null if(node.getRightChild() == null && node.getLeftChild() != null) { successor = node.getLeftChild(); x = successor; parentOfx = node.parent; } //case 3 - 4: all is not null if(node.getLeftChild() != null && node.getRightChild() != null) { //find successor successor = node.getRightChild(); while(successor.getLeftChild() != null) { successor = successor.getLeftChild(); } //x = successor.right x = successor.getRightChild(); //case 3: if node is parent of the successor if(node == successor.getParent()) { //x's parent does not changed parentOfx = successor; //node.left transplant to left of successor this.transPlantToLeft(node.getLeftChild(), successor); successor.setColor(originColor); } else //case 4: if node is not parent of the successor { //need change x's parent to origin successor's parent parentOfx = successor.getParent(); this.transPlantToLeft(node.getLeftChild(), successor); this.replaceAndTransPlant(successor, x); this.transPlantToRight(node.getRightChild(), successor); successor.setColor(originColor); } } //to replace this.replaceAndTransPlant(node, successor); if(node == this.getRoot()) { this.setRoot(successor); } return new Object[]{x, parentOfx, originColor}; } /** * fix to rb-tree feature * @param node * @param parent */ private void removeFixup(Node node, Node parent) { if(node == null && parent == null) { return; } // node is null or black and not root of this tree while ((node == null || node.getColor() == Node.NodeColors.BLACK) && node != this.getRoot()) { Node brother = this.getBrother(node, parent); // left of parent if(node == parent.getLeftChild()) { // case 2: brother is red if(brother != null && brother.getColor() == Node.NodeColors.RED) { parent.setColor(Node.NodeColors.RED); brother.setColor(Node.NodeColors.BLACK); this.leftRotate(this, parent); brother = this.getBrother(node, parent); assert brother == null || brother.getColor() == Node.NodeColors.BLACK; assert parent == null || parent.getColor() == Node.NodeColors.RED; } // case 3 - 5: brother is black. // case 3: brother's children are all black if(brother != null && (brother.getLeftChild() == null || brother.getLeftChild().getColor() == Node.NodeColors.BLACK) && (brother.getRightChild() == null || brother.getRightChild().getColor() == Node.NodeColors.BLACK)) { brother.setColor(Node.NodeColors.RED); node = parent; parent = node.getParent(); brother = this.getBrother(node, parent); // continue; } else // case 4 - 5: { // case 4: brother left is red, and right is black if(brother != null && (brother.getRightChild() == null || brother.getRightChild().getColor() == Node.NodeColors.BLACK)) { brother.setColor(Node.NodeColors.RED); brother.getLeftChild().setColor(Node.NodeColors.BLACK); this.rightRotate(this, brother); brother = this.getBrother(node, parent); } // case 5: right is red if(brother != null) { brother.setColor(parent.getColor()); } parent.setColor(Node.NodeColors.BLACK); if(brother != null && brother.getRightChild() != null) { brother.getRightChild().setColor(Node.NodeColors.RED); } this.leftRotate(this, parent); // redeay to exit; node = this.getRoot(); } } else// right of parent { // case 2: brother is red if(brother.getColor() == Node.NodeColors.RED) { brother.setColor(Node.NodeColors.BLACK); parent.setColor(Node.NodeColors.RED); this.rightRotate(this, parent); brother = this.getBrother(node, parent); assert brother == null || brother.getColor() == Node.NodeColors.BLACK; assert parent == null || parent.getColor() == Node.NodeColors.RED; } // case 3 - 5: brother is black // case 3: both brother's children are blcak if(brother != null &&(brother.getLeftChild() == null || brother.getLeftChild().getColor() == Node.NodeColors.BLACK) && (brother.getRightChild() == null || brother.getRightChild().getColor() == Node.NodeColors.BLACK)) { brother.setColor(Node.NodeColors.RED); node = parent; parent = node.getParent(); brother = this.getBrother(node, parent); // continue; } else // case 4 - 5: { // case 4: brother left is black, right is red if (brother != null && (brother.getLeftChild() == null || brother.getLeftChild().getColor() == Node.NodeColors.BLACK)) { brother.setColor(Node.NodeColors.RED); brother.getRightChild().setColor(Node.NodeColors.BLACK); this.leftRotate(this, brother); brother = this.getBrother(node, parent); } // case 5: left is red if(brother != null) { brother.setColor(parent.getColor()); } parent.setColor(Node.NodeColors.BLACK); if(brother != null && brother.getLeftChild() != null) { brother.getLeftChild().setColor(Node.NodeColors.RED); } this.rightRotate(this, parent); // redeay to exit; node = this.getRoot(); } } } //case 1: node color to back if(node != null) { node.setColor(Node.NodeColors.BLACK); } } /** * replace oring use replace */ @SuppressWarnings("unchecked") public void replaceAndTransPlant(Node origin, Node replace) { //origin's parent Node parent = origin.getParent(); if(replace != null) { replace.setParent(parent); } //parent is null to return if(parent != null) { //if origin is left node if(parent.getLeftChild() == origin) { parent.setLeftChild(replace); } else //else is right { parent.setRightChild(replace); } } } /** * transplant node to left of parent * @param node * @param parent */ @SuppressWarnings("unchecked") private void transPlantToLeft(Node node, Node parent) { if(parent != null) { parent.setLeftChild(node); } if(node != null) { node.setParent(parent); } } /** * transplant node to right of parent * @param node * @param parent */ @SuppressWarnings("unchecked") private void transPlantToRight(Node node, Node parent) { if(parent != null) { parent.setRightChild(node); } if(node != null) { node.setParent(parent); } } /** * 获取兄弟节点 * @param node * @param parent * @return */ private Node getBrother(Node node, Node parent) { if(parent == null) { return null; } return node == parent.getLeftChild()? parent.getRightChild(): parent.getLeftChild(); } /** * node left rotate */ private void leftRotate(RBTree tree, Node node) { if(node.rightChild == null) { return; } Node rightChild = node.rightChild; //change parent child reference if(node.parent != null) { //if is left node if(node.parent.leftChild == node) { node.parent.leftChild = rightChild; } else //if is right node { node.parent.rightChild = rightChild; } } else //if node is root of the tree { tree.root = rightChild; tree.getRoot().setParent(null); } //change node and node.right child's parent rightChild.parent = node.parent; //set parent of the node node.parent = rightChild; node.rightChild = rightChild.leftChild; if(node.leftChild != null) { node.leftChild.parent = node; } rightChild.leftChild = node; } /** * node right rotate */ private void rightRotate(RBTree tree, Node node) { //can not to rotate if(node.leftChild == null) { return; } Node leftChild = node.leftChild; //change parent of this nodes if(node.parent != null) { if(node == node.parent.leftChild) { node.parent.leftChild = leftChild; } else { node.parent.rightChild = leftChild; } } else //if node is root of the tree { tree.root = node.leftChild; tree.getRoot().setParent(null); } //change parent of the node.left leftChild.parent = node.parent; node.parent = leftChild; node.leftChild = leftChild.rightChild; if(node.leftChild != null) { node.leftChild.parent = node; } leftChild.rightChild = node; } /** * rb-tree's node * @param <K> * @param <V> */ public static class Node<K,V> { Node<K, V> parent; Node<K, V> leftChild; Node<K, V> rightChild; K key; V value; public K getKey() { return key; } public void setKey(K key) { this.key = key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; } NodeColors color = NodeColors.RED; public Node<K, V> getParent() { return parent; } public void setParent(Node<K, V> parent) { this.parent = parent; } public Node<K, V> getLeftChild() { return leftChild; } public void setLeftChild(Node<K, V> leftChild) { this.leftChild = leftChild; } public Node<K, V> getRightChild() { return rightChild; } public void setRightChild(Node<K, V> rightChild) { this.rightChild = rightChild; } public NodeColors getColor() { return color; } public void setColor(NodeColors color) { this.color = color; } /** * rb-trees's child node colors */ public enum NodeColors { RED, BLACK } @Override public String toString() { return "Node{" + "key=" + key + '}'; } } /** * comparetor * @param <T> */ public interface Comparetor<T> { /** * 比较 t1 和 t2 * @param t1 * @param t2 * @return t1 > t2 return 1 * t1 == t2 return 0 * t1 < t2 return -1 */ int compare(T t1, T t2); } }

 

 

 

 

 

 

 

 

 

package org.xlj; import org.junit.Test; public class RBTreeTest { @Test public void insertTest() { RBTree<Integer, Integer> tree = new RBTree<>(); tree.setComparetor(new RBTree.Comparetor<Integer>() { @Override public int compare(Integer t1, Integer t2) { return t1 > t2 ? 1 : t1 == t2 ? 0 : - 1; } }); try { // int[] values={8, 12, 31, 19, 40, 38}; int[] values={40, 38, 31, 12, 19, 8}; for (int i = 0; i < values.length; i++) { RBTree.Node<Integer, Integer> node = new RBTree.Node<>(); node.setKey(values[i]); node.setValue(values[i]); tree.insert(node); } } catch (Exception e) { e.printStackTrace(); } this.printTree(tree.root, 0); System.out.println(); System.out.println(); try { System.out.println("remove :" + tree.get(19).getKey() + " " + tree.get(19).getColor()); tree.remove(38); tree.remove(19); } catch (Exception e) { e.printStackTrace(); } this.printTree(tree.root, 0); // while (tree.getRoot() != null) // { // System.out.println(); // System.out.println(); // try // { // System.out.println("remove :" + tree.getRoot().getKey() + " " + tree.getRoot().getColor()); // tree.remove(tree.getRoot().getKey()); // } catch (Exception e) { // e.printStackTrace(); // } // this.printTree(tree.root, 0); // } } public void printTree(RBTree.Node node, int index) { if(node == null) { return; } System.out.println(node.getKey() + " " + node.getColor() + " " + index++); this.printTree(node.getLeftChild(), index); this.printTree(node.getRightChild(), index); index--; } }
转载请注明原文地址: https://www.6miu.com/read-5028382.html

最新回复(0)