红黑树(Red-Black Tree)

devtools/2024/11/30 14:31:24/

        红黑树(Red-Black Tree)是一种自平衡的二叉查找树,它具有以下特性: 1. 每个节点要么是红色,要么是黑色。 2. 根节点是黑色的。 3. 每个叶子节点(NIL节点)是黑色的。 4. 如果一个节点是红色的,则它的子节点必须是黑色的(反之不一定成立)。 5. 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。 

        红黑树简单实现;

java">public class RedBlackTree {private static final boolean RED = true;private static final boolean BLACK = false;private Node root;private class Node {int key;String value;Node left, right;boolean color;public Node(int key, String value, boolean color) {this.key = key;this.value = value;this.color = color;}}private boolean isRed(Node node) {if (node == null) {return false;}return node.color == RED;}// 左旋抓private Node rotateLeft(Node h) {Node x = h.right;h.right = x.left;x.left = h;x.color = h.color;h.color = RED;return x;}// 右旋转private Node rotateRight(Node h) {Node x = h.left;h.left = x.right;x.right = h;x.color = h.color;h.color = RED;return x;}// 转换颜色private void flipColors(Node h) {h.color = RED;h.left.color = BLACK;h.right.color = BLACK;}// 插入操作public void put(int key, String value) {root = put(root, key, value);root.color = BLACK;}private Node put(Node h, int key, String value) {if (h == null) {return new Node(key, value, RED);}if (key < h.key) {h.left = put(h.left, key, value);} else if (key > h.key) {h.right = put(h.right, key, value);} else {h.value = value;}// 红黑树平衡操作if (isRed(h.right) && !isRed(h.left)) {h = rotateLeft(h);}if (isRed(h.left) && isRed(h.left.left)) {h = rotateRight(h);}if (isRed(h.left) && isRed(h.right)) {flipColors(h);}return h;}// 对外暴露的查询方法public String get(int key) {return get(root, key);}// 递归查询操作private String get(Node x, int key) {if (x == null) {return null;}if (key < x.key) {return get(x.left, key);} else if (key > x.key) {return get(x.right, key);} else {return x.value;}}// 删除操作public void delete(int key) {if (root == null) {return;}if (!isRed(root.left) && !isRed(root.right)){root.color = RED;}root = delete(root, key);if (root != null) {root.color = BLACK;}}private Node delete(Node h, int key) {if (h == null) {return null;}if (key < h.key) {if (!isRed(h.left) && !isRed(h.left.left)) {h = moveRedLeft(h);}h.left = delete(h.left, key);} else {if (isRed(h.left)) {h = rotateRight(h);}if (key == h.key && (h.right == null)) {return h.left; // Corrected to delete the node directly}if (!isRed(h.right) && !isRed(h.right.left)) {h = moveRedRight(h);}if (key == h.key) {Node x = min(h.right);h.key = x.key;h.value = x.value;h.right = deleteMin(h.right);} else {h.right = delete(h.right, key);}}return balance(h);}private Node moveRedLeft(Node h) {flipColors(h);if (isRed(h.right.left)) {h.right = rotateRight(h.right);h = rotateLeft(h);flipColors(h);}return h;}private Node moveRedRight(Node h) {flipColors(h);if (isRed(h.left.left)) {h = rotateRight(h);flipColors(h);}return h;}private Node deleteMin(Node h) {if (h.left == null) {return null;}if (!isRed(h.left) && !isRed(h.left.left)) {h = moveRedLeft(h);}h.left = deleteMin(h.left);return balance(h);}private Node min(Node x) {while (x.left != null) {x = x.left;}return x;}private Node balance(Node h) {if (isRed(h.right)) {h = rotateLeft(h);}if (isRed(h.left) && isRed(h.left.left)) {h = rotateRight(h);}if (isRed(h.left) && isRed(h.right)) {flipColors(h);}return h;}
}

         红黑树实战实现:

java">public class RBTreeNode<T extends Comparable<T>> {private T value;//node valueprivate RBTreeNode<T> left;//left child pointerprivate RBTreeNode<T> right;//right child pointerprivate RBTreeNode<T> parent;//parent pointerprivate boolean red;//color is red or not redpublic RBTreeNode(){}public RBTreeNode(T value){this.value=value;}public RBTreeNode(T value,boolean isRed){this.value=value;this.red = isRed;}public T getValue() {return value;}void setValue(T value) {this.value = value;}RBTreeNode<T> getLeft() {return left;}void setLeft(RBTreeNode<T> left) {this.left = left;}RBTreeNode<T> getRight() {return right;}void setRight(RBTreeNode<T> right) {this.right = right;}RBTreeNode<T> getParent() {return parent;}void setParent(RBTreeNode<T> parent) {this.parent = parent;}boolean isRed() {return red;}boolean isBlack(){return !red;}/*** is leaf node**/boolean isLeaf(){return left==null && right==null;}void setRed(boolean red) {this.red = red;}void makeRed(){red=true;}void makeBlack(){red=false;}@Overridepublic String toString(){return value.toString();}
}public class RBTree<T extends Comparable<T>> {private final RBTreeNode<T> root;//node numberprivate java.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.private volatile boolean overrideMode=true;public RBTree(){this.root = new RBTreeNode<T>();}public RBTree(boolean overrideMode){this();this.overrideMode=overrideMode;}public boolean isOverrideMode() {return overrideMode;}public void setOverrideMode(boolean overrideMode) {this.overrideMode = overrideMode;}/*** number of tree number* @return*/public long getSize() {return size.get();}/*** get the root node* @return*/private RBTreeNode<T> getRoot(){return root.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*/public T addNode(T value){RBTreeNode<T> t = new RBTreeNode<T>(value);return addNode(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*/public T find(T value){RBTreeNode<T> dataRoot = getRoot();while(dataRoot!=null){int cmp = dataRoot.getValue().compareTo(value);if(cmp<0){dataRoot = dataRoot.getRight();}else if(cmp>0){dataRoot = dataRoot.getLeft();}else{return dataRoot.getValue();}}return null;}/*** 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*/public T remove(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();}else if(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);}else if(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();return dataRoot.getValue();}}return null;}/*** fix remove action* @param node* @param isParent*/private void fixRemove(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);}else if(sibling.isRed() && isLeft){//cur in leftparent.makeRed();sibling.makeBlack();rotateLeft(parent);}else if(isBlack(sibling.getLeft()) && isBlack(sibling.getRight())){//case 2sibling.makeRed();cur = parent;isRed = cur.isRed();parent=parent.getParent();}else if(isLeft && !isBlack(sibling.getLeft()) && isBlack(sibling.getRight())){//case 3sibling.makeRed();sibling.getLeft().makeBlack();rotateRight(sibling);}else if(!isLeft && !isBlack(sibling.getRight()) && isBlack(sibling.getLeft()) ){sibling.makeRed();sibling.getRight().makeBlack();rotateLeft(sibling);}else if(isLeft && !isBlack(sibling.getRight())){//case 4sibling.setRed(parent.isRed());parent.makeBlack();sibling.getRight().makeBlack();rotateLeft(parent);cur=getRoot();}else if(!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 nodeprivate RBTreeNode<T> getSibling(RBTreeNode<T> node,RBTreeNode<T> parent){parent = node==null ? parent : node.getParent();if(node==null){return parent.getLeft()==null ? parent.getRight() : parent.getLeft();}if(node==parent.getLeft()){return parent.getRight();}else{return parent.getLeft();}}private boolean isBlack(RBTreeNode<T> node){return node==null || node.isBlack();}private boolean isRoot(RBTreeNode<T> node){return root.getLeft() == node && node.getParent()==null;}/*** find the successor node* @param node current node's right node* @return*/private RBTreeNode<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;}private T addNode(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;}else if(cmp==0){//value exists,ignore this nodereturn x.getValue();}setParent(node,x);if(cmp>0){x.setLeft(node);}else{x.setRight(node);}fixInsert(node);size.incrementAndGet();}return null;}/*** find the parent node to hold node x,if parent value equals x.value return parent.* @param x* @return*/private RBTreeNode<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();}else if(cmp<0){dataRoot = child;child = child.getRight();}}return dataRoot;}/*** red black tree insert fix.* @param x*/private void fixInsert(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*/private RBTreeNode<T> getUncle(RBTreeNode<T> node){RBTreeNode<T> parent = node.getParent();RBTreeNode<T> ancestor = parent.getParent();if(ancestor==null){return null;}if(parent == ancestor.getLeft()){return ancestor.getRight();}else{return ancestor.getLeft();}}private void rotateLeft(RBTreeNode<T> node){RBTreeNode<T> right = node.getRight();if(right==null){throw new 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);}}private void rotateRight(RBTreeNode<T> node){RBTreeNode<T> left = node.getLeft();if(left==null){throw new 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);}}private void setParent(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*/public void printTree(RBTreeNode<T> root){java.util.LinkedList<RBTreeNode<T>> queue =new java.util.LinkedList<RBTreeNode<T>>();java.util.LinkedList<RBTreeNode<T>> queue2 =new java.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;}}}public static void main(String[] args) {RBTree<String> bst = new RBTree<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());}
}


http://www.ppmy.cn/devtools/4824.html

相关文章

安全地创建一个临时文件 - mkstemp

安全地创建一个临时文件 - mkstemp 在我们处理一些敏感数据的时候&#xff0c;可能必须要临时存储在文件中&#xff0c;这个时候就需要创建临时文件&#xff1b; 在我们需要临时创建一些大量的中间数据&#xff0c;并且在程序结束时删除这些文件时&#xff0c;我们就需要创建临…

软考131-上午题-【软件工程】-软件可靠性、可用性、可维护性

可靠性、可用性和可维护性是软件的质量属性&#xff0c;软件工程中&#xff0c;用 0-1 之间的数来度量。 0.66 66% 1、 可靠性 可靠性是指一个系统对于给定的时间间隔内、在给定条件下无失效运作的概率。 可以用 MTTF/ (1MTTF) 来度量&#xff0c;其中 MTTF 为平均无故障时间…

Python和R概率统计算法建模评估气象和运动

&#x1f3af;要点 概率统计数学&#xff1a;&#x1f3af;Python和R计算和算法实现气象学&#xff1a; 计算和可视化&#xff1a;&#x1f3af;全球陆地-海洋平均年平均表面温度&#xff1a;&#x1f58a;直方图温度异常&#xff0c;&#x1f58a;显示分位数-分位数&#xff…

postman 调试 传base64字符串 原来选xml

上个图 工具类 package org.springblade.common.utils;import com.alibaba.fastjson.JSONObject; import org.springblade.modules.tc.mas.Submit;import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStrea…

csdn的编写教程(官方给的)

自定义的目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注脚…

Axios的简明教程

Axios是什么&#xff1f; Axios是一个基于promise的HTTP客户端&#xff0c;可以在浏览器和node.js中使用。它提供了一种简单的方法来发送异步HTTP请求。与其他HTTP库&#xff08;如Fetch&#xff09;相比&#xff0c;Axios提供了更丰富的功能和更好的错误处理。例如&#xff0…

探索C语言数据结构:利用顺序表完成通讯录的实现

在好久之前我就已经学习过顺序表&#xff0c;但是在前几天再次温习顺序表的时候&#xff0c;我惊奇的发现顺序编表可以完成我们日常使用的通讯录的功能&#xff0c;那么今天就来好好通过博客总结一下通讯录如何完成吧。 常常会回顾努力的自己&#xff0c;所以要给自己的努力留…

mysql 日环比 统计

接到一个任务&#xff0c;要计算日环比的情况。 16、查询销售额日环比情况 日环比&#xff1a; &#xff08;今日-昨日&#xff09;/ 昨日 的一个比率情况。 1&#xff0c;建表 DROP TABLE IF EXISTS sale; create table sale(id int not null AUTO_INCREMENT,record_date da…