T key = a search keyNode root = point to the root of a BSTwhile(true){if(root==null){break; }if(root.value.equals(key)){return root; }elseif(key.compareTo(root.value)<0){ root =root.left; }else{ root =root.right; }}returnnull;
从程序中可以看出,当BST查找的时候,先与当前节点进行比较:
如果相等的话就返回当前节点。
如果少于当前节点则继续查找当前节点的左节点。
如果大于当前节点则继续查找当前节点的右节点。
直到当前节点指针为空或者查找到对应的节点,程序查找结束。
1.2 BST的插入操作
Node node = create a new node with specify valueNode root = point the root node of a BSTNode parent =null;//find the parent node to append the new nodewhile(true){if(root==null)break; parent = root;if(node.value.compareTo(root.value)<=0){ root =root.left; }else{ root =root.right; } }if(parent!=null){if(node.value.compareTo(parent.value)<=0){//append to leftparent.left= node; }else{//append to rightparent.right= node; }}
publicclassRBTreeNode<TextendsComparable<T>> {privateT value;//node valueprivateRBTreeNode<T> left;//left child pointerprivateRBTreeNode<T> right;//right child pointerprivateRBTreeNode<T> parent;//parent pointerprivateboolean red;//color is red or not redpublicRBTreeNode(){}publicRBTreeNode(T value){this.value=value;}publicRBTreeNode(T value,boolean isRed){this.value=value;this.red= isRed;}publicTgetValue() {return value; }voidsetValue(T value) {this.value= value; }RBTreeNode<T> getLeft() {return left; }voidsetLeft(RBTreeNode<T> left) {this.left= left; }RBTreeNode<T> getRight() {return right; }voidsetRight(RBTreeNode<T> right) {this.right= right; }RBTreeNode<T> getParent() {return parent; }voidsetParent(RBTreeNode<T> parent) {this.parent= parent; }booleanisRed() {return red; }booleanisBlack(){return!red; } /** * is leaf node **/booleanisLeaf(){return left==null&& right==null; }voidsetRed(boolean red) {this.red= red; }voidmakeRed(){ red=true; }voidmakeBlack(){ red=false; } @OverridepublicStringtoString(){returnvalue.toString(); }}publicclassRBTree<TextendsComparable<T>> {privatefinalRBTreeNode<T> root;//node numberprivatejava.util.concurrent.atomic.AtomicLong size =new java.util.concurrent.atomic.AtomicLong(0);//in overwrite mode,all node's value can not has same value//in non-overwrite mode,node can have same value, suggest don't use non-overwrite mode.privatevolatileboolean overrideMode=true;publicRBTree(){this.root=newRBTreeNode<T>(); }publicRBTree(boolean overrideMode){this();this.overrideMode=overrideMode; }publicbooleanisOverrideMode() {return overrideMode; }publicvoidsetOverrideMode(boolean overrideMode) {this.overrideMode= overrideMode; } /** * number of tree number * @return */publiclonggetSize() {returnsize.get(); } /** * get the root node * @return */privateRBTreeNode<T> getRoot(){returnroot.getLeft(); } /** * add value to a new node,if this value exist in this tree, * if value exist,it will return the exist value.otherwise return null * if override mode is true,if value exist in the tree, * it will override the old value in the tree * * @param value * @return */publicTaddNode(T value){RBTreeNode<T> t =newRBTreeNode<T>(value);returnaddNode(t); } /** * find the value by give value(include key,key used for search, * other field is not used,@see compare method).if this value not exist return null * @param value * @return */publicTfind(T value){RBTreeNode<T> dataRoot =getRoot();while(dataRoot!=null){int cmp =dataRoot.getValue().compareTo(value);if(cmp<0){ dataRoot =dataRoot.getRight(); }elseif(cmp>0){ dataRoot =dataRoot.getLeft(); }else{returndataRoot.getValue(); } }returnnull; } /** * remove the node by give value,if this value not exists in tree return null * @param value include search key * @return the value contain in the removed node */publicTremove(T value){RBTreeNode<T> dataRoot =getRoot();RBTreeNode<T> parent = root;while(dataRoot!=null){int cmp =dataRoot.getValue().compareTo(value);if(cmp<0){ parent = dataRoot; dataRoot =dataRoot.getRight(); }elseif(cmp>0){ parent = dataRoot; dataRoot =dataRoot.getLeft(); }else{if(dataRoot.getRight()!=null){RBTreeNode<T> min =removeMin(dataRoot.getRight());//x used for fix color balanceRBTreeNode<T> x =min.getRight()==null?min.getParent() :min.getRight();boolean isParent =min.getRight()==null;min.setLeft(dataRoot.getLeft());setParent(dataRoot.getLeft(),min);if(parent.getLeft()==dataRoot){parent.setLeft(min); }else{parent.setRight(min); }setParent(min,parent);boolean curMinIsBlack =min.isBlack();//inherit dataRoot's colormin.setRed(dataRoot.isRed());if(min!=dataRoot.getRight()){min.setRight(dataRoot.getRight());setParent(dataRoot.getRight(),min); }//remove a black node,need fix colorif(curMinIsBlack){if(min!=dataRoot.getRight()){fixRemove(x,isParent); }elseif(min.getRight()!=null){fixRemove(min.getRight(),false); }else{fixRemove(min,true); } } }else{setParent(dataRoot.getLeft(),parent);if(parent.getLeft()==dataRoot){parent.setLeft(dataRoot.getLeft()); }else{parent.setRight(dataRoot.getLeft()); }//current node is black and tree is not emptyif(dataRoot.isBlack() &&!(root.getLeft()==null)){RBTreeNode<T> x =dataRoot.getLeft()==null? parent :dataRoot.getLeft();boolean isParent =dataRoot.getLeft()==null;fixRemove(x,isParent); } }setParent(dataRoot,null);dataRoot.setLeft(null);dataRoot.setRight(null);if(getRoot()!=null){getRoot().setRed(false);getRoot().setParent(null); }size.decrementAndGet();returndataRoot.getValue(); } }returnnull; } /** * fix remove action * @param node * @param isParent */privatevoidfixRemove(RBTreeNode<T> node,boolean isParent){RBTreeNode<T> cur = isParent ?null: node;boolean isRed = isParent ?false:node.isRed();RBTreeNode<T> parent = isParent ? node :node.getParent();while(!isRed &&!isRoot(cur)){RBTreeNode<T> sibling =getSibling(cur,parent);//sibling is not null,due to before remove tree color is balance//if cur is a left nodeboolean isLeft =parent.getRight()==sibling;if(sibling.isRed() &&!isLeft){//case 1//cur in rightparent.makeRed();sibling.makeBlack();rotateRight(parent); }elseif(sibling.isRed() && isLeft){//cur in leftparent.makeRed();sibling.makeBlack();rotateLeft(parent); }elseif(isBlack(sibling.getLeft())&&isBlack(sibling.getRight())){//case 2sibling.makeRed(); cur = parent; isRed =cur.isRed(); parent=parent.getParent(); }elseif(isLeft &&!isBlack(sibling.getLeft())&&isBlack(sibling.getRight())){//case 3sibling.makeRed();sibling.getLeft().makeBlack();rotateRight(sibling); }elseif(!isLeft &&!isBlack(sibling.getRight())&&isBlack(sibling.getLeft()) ){sibling.makeRed();sibling.getRight().makeBlack();rotateLeft(sibling); }elseif(isLeft &&!isBlack(sibling.getRight())){//case 4sibling.setRed(parent.isRed());parent.makeBlack();sibling.getRight().makeBlack();rotateLeft(parent); cur=getRoot(); }elseif(!isLeft &&!isBlack(sibling.getLeft())){sibling.setRed(parent.isRed());parent.makeBlack();sibling.getLeft().makeBlack();rotateRight(parent); cur=getRoot(); } }if(isRed){cur.makeBlack(); }if(getRoot()!=null){getRoot().setRed(false);getRoot().setParent(null); } }//get sibling nodeprivateRBTreeNode<T> getSibling(RBTreeNode<T> node,RBTreeNode<T> parent){ parent = node==null? parent :node.getParent();if(node==null){returnparent.getLeft()==null?parent.getRight() :parent.getLeft(); }if(node==parent.getLeft()){returnparent.getRight(); }else{returnparent.getLeft(); } }privatebooleanisBlack(RBTreeNode<T> node){return node==null||node.isBlack(); }privatebooleanisRoot(RBTreeNode<T> node){returnroot.getLeft() == node &&node.getParent()==null; } /** * find the successor node * @param node current node's right node * @return */privateRBTreeNode<T> removeMin(RBTreeNode<T> node){//find the min nodeRBTreeNode<T> parent = node;while(node!=null&&node.getLeft()!=null){ parent = node; node =node.getLeft(); }//remove min nodeif(parent==node){return node; }parent.setLeft(node.getRight());setParent(node.getRight(),parent);//don't remove right pointer,it is used for fixed color balance//node.setRight(null);return node; }privateTaddNode(RBTreeNode<T> node){node.setLeft(null);node.setRight(null);node.setRed(true);setParent(node,null);if(root.getLeft()==null){root.setLeft(node);//root node is blacknode.setRed(false);size.incrementAndGet(); }else{RBTreeNode<T> x =findParentNode(node);int cmp =x.getValue().compareTo(node.getValue());if(this.overrideMode&& cmp==0){T v =x.getValue();x.setValue(node.getValue());return v; }elseif(cmp==0){//value exists,ignore this nodereturnx.getValue(); }setParent(node,x);if(cmp>0){x.setLeft(node); }else{x.setRight(node); }fixInsert(node);size.incrementAndGet(); }returnnull; } /** * find the parent node to hold node x,if parent value equals x.value return parent. * @param x * @return */privateRBTreeNode<T> findParentNode(RBTreeNode<T> x){RBTreeNode<T> dataRoot =getRoot();RBTreeNode<T> child = dataRoot;while(child!=null){int cmp =child.getValue().compareTo(x.getValue());if(cmp==0){return child; }if(cmp>0){ dataRoot = child; child =child.getLeft(); }elseif(cmp<0){ dataRoot = child; child =child.getRight(); } }return dataRoot; } /** * red black tree insert fix. * @param x */privatevoidfixInsert(RBTreeNode<T> x){RBTreeNode<T> parent =x.getParent();while(parent!=null&&parent.isRed()){RBTreeNode<T> uncle =getUncle(x);if(uncle==null){//need to rotateRBTreeNode<T> ancestor =parent.getParent();//ancestor is not null due to before before add,tree color is balanceif(parent ==ancestor.getLeft()){boolean isRight = x ==parent.getRight();if(isRight){rotateLeft(parent); }rotateRight(ancestor);if(isRight){x.setRed(false); parent=null;//end loop }else{parent.setRed(false); }ancestor.setRed(true); }else{boolean isLeft = x ==parent.getLeft();if(isLeft){rotateRight(parent); }rotateLeft(ancestor);if(isLeft){x.setRed(false); parent=null;//end loop }else{parent.setRed(false); }ancestor.setRed(true); } }else{//uncle is redparent.setRed(false);uncle.setRed(false);parent.getParent().setRed(true); x=parent.getParent(); parent =x.getParent(); } }getRoot().makeBlack();getRoot().setParent(null); } /** * get uncle node * @param node * @return */privateRBTreeNode<T> getUncle(RBTreeNode<T> node){RBTreeNode<T> parent =node.getParent();RBTreeNode<T> ancestor =parent.getParent();if(ancestor==null){returnnull; }if(parent ==ancestor.getLeft()){returnancestor.getRight(); }else{returnancestor.getLeft(); } }privatevoidrotateLeft(RBTreeNode<T> node){RBTreeNode<T> right =node.getRight();if(right==null){thrownew java.lang.IllegalStateException("right node is null"); }RBTreeNode<T> parent =node.getParent();node.setRight(right.getLeft());setParent(right.getLeft(),node);right.setLeft(node);setParent(node,right);if(parent==null){//node pointer to root//right raise to root noderoot.setLeft(right);setParent(right,null); }else{if(parent.getLeft()==node){parent.setLeft(right); }else{parent.setRight(right); }//right.setParent(parent);setParent(right,parent); } }privatevoidrotateRight(RBTreeNode<T> node){RBTreeNode<T> left =node.getLeft();if(left==null){thrownew java.lang.IllegalStateException("left node is null"); }RBTreeNode<T> parent =node.getParent();node.setLeft(left.getRight());setParent(left.getRight(),node);left.setRight(node);setParent(node,left);if(parent==null){root.setLeft(left);setParent(left,null); }else{if(parent.getLeft()==node){parent.setLeft(left); }else{parent.setRight(left); }setParent(left,parent); } }privatevoidsetParent(RBTreeNode<T> node,RBTreeNode<T> parent){if(node!=null){node.setParent(parent);if(parent==root){node.setParent(null); } } } /** * debug method,it used print the given node and its children nodes, * every layer output in one line * @param root */publicvoidprintTree(RBTreeNode<T> root){java.util.LinkedList<RBTreeNode<T>> queue =newjava.util.LinkedList<RBTreeNode<T>>();java.util.LinkedList<RBTreeNode<T>> queue2 =newjava.util.LinkedList<RBTreeNode<T>>();if(root==null){return ; }queue.add(root);boolean firstQueue =true;while(!queue.isEmpty() ||!queue2.isEmpty()){java.util.LinkedList<RBTreeNode<T>> q = firstQueue ? queue : queue2;RBTreeNode<T> n =q.poll();if(n!=null){String pos =n.getParent()==null?"": ( n ==n.getParent().getLeft() ?" LE":" RI");String pstr =n.getParent()==null?"":n.getParent().toString();String cstr =n.isRed()?"R":"B"; cstr =n.getParent()==null? cstr : cstr+" ";System.out.print(n+"("+(cstr)+pstr+(pos)+")"+"\t");if(n.getLeft()!=null){ (firstQueue ? queue2 : queue).add(n.getLeft()); }if(n.getRight()!=null){ (firstQueue ? queue2 : queue).add(n.getRight()); } }else{System.out.println(); firstQueue =!firstQueue; } } }publicstaticvoidmain(String[] args) {RBTree<String> bst =newRBTree<String>();bst.addNode("d");bst.addNode("d");bst.addNode("c");bst.addNode("c");bst.addNode("b");bst.addNode("f");bst.addNode("a");bst.addNode("e");bst.addNode("g");bst.addNode("h");bst.remove("c");bst.printTree(bst.getRoot()); }}
代码调试的时候,printTree输出格式如下:
d(B)b(B d LE)g(R d RI)a(R b LE)e(B g LE)h(B g RI)f(R e RI)