zoukankan      html  css  js  c++  java
  • 数据结构——红黑树

    红黑树也是一种平衡二叉查找树,经常用于替代AVL树,特点如下:

    1. 根节点为黑色的,空节点也看做黑色节点;
    2. 红色节点的子节点一定为黑色,任何一条路径不能出现两个连续的红节点
    3. 从任何一个节点出发,到空节点的路径上包含相同数目的黑节点,即如果忽略路径中的红色节点,红黑树是完全平衡的。

      相对于AVL树,红黑树能够以O(log2 n) 的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。当然,红黑树并不适应所有应用树的领域。如果数据基本上是静态的,那么让他们待在他们能够插入,并且不影响平衡的地方会具有更好的性能。如果数据完全是静态的,例如,做一个哈希表,性能可能会更好一些。
      红黑树是一个更高效的检索二叉树,因此常常用来实现关联数组。典型地,JDK 提供的集合类 TreeMap 本身就是一个红黑树的实现。对于 TreeMap 而言,由于它底层采用一棵“红黑树”来保存集合中的 Entry,这意味这 TreeMap 添加元素、取出元素的性能都比 HashMap 低:当 TreeMap 添加元素时,需要通过循环找到新增 Entry 的插入位置,因此比较耗性能;当从 TreeMap 中取出元素时,需要通过循环才能找到合适的 Entry,也比较耗性能。但 TreeMap、TreeSet (TreeSet 底层是通过 TreeMap 来实现的)比 HashMap、HashSet 的优势在于:TreeMap 中的所有 Entry 总是按 key 根据指定排序规则保持有序状态,TreeSet 中所有元素总是根据指定排序规则保持有序状态。

    用途:

    AVL树:最早的平衡二叉树之一。应用相对其他数据结构比较少。windows对进程地址空间的管理用到了AVL树
    红黑树:平衡二叉树,广泛用在C++的STL中。map和set都是用红黑树实现的。
    B/B+树用在磁盘文件组织 数据索引和数据库索引

    插入、删除思路:《算法导论》第13章

    Java实现如下:

      1 package com.tonyluis;
      2 
      3 public class RBTree {
      4     
      5     //空节点
      6     private final Node NIL = new Node(null,null,null,Color.BLACK,-1);
      7     private Node root;
      8     
      9     public RBTree() {
     10         root = NIL;
     11     }
     12     
     13     public RBTree(Node  root) {
     14         this.root = root;
     15     }
     16     
     17     
     18     //插入节点
     19     public void rbInsert(Node node) {
     20         
     21         Node previous = NIL;
     22         Node temp = root;
     23         
     24         while (temp != NIL) {
     25             previous = temp;
     26             if (temp.getValue() < node.getValue()) {
     27                 temp = temp.getRight();
     28             } else {
     29                 temp = temp.getLeft();
     30             }
     31         }
     32         node.setParent(previous);
     33         
     34         if (previous == NIL) {
     35             root = node;
     36             root.setParent(NIL);
     37         } else  if (previous.getValue() > node.getValue()) {
     38             previous.setLeft(node);
     39         } else {
     40             previous.setRight(node);
     41         }
     42         
     43         node.setLeft(NIL);
     44         node.setRight(NIL);
     45         node.setColor(Color.RED);
     46         rb_Insert_Fixup(node);
     47         
     48     }
     49     
     50     //插入节点后的调整
     51     private void rb_Insert_Fixup(Node node) {
     52     
     53         while (node.getParent().getColor() == Color.RED) {
     54             
     55             if (node.getParent() == node.getParent().getParent().getLeft()) {
     56                 
     57                 Node rightNuncle = node.getParent().getParent().getRight();
     58                 
     59                 if (rightNuncle.getColor() == Color.RED) {         //Case 1
     60                     
     61                     rightNuncle.setColor(Color.BLACK);
     62                     node.getParent().setColor(Color.BLACK);
     63                     node.getParent().getParent().setColor(Color.RED);
     64                     node = node.getParent().getParent();
     65                                         
     66                 } else if (node == node.getParent().getRight()) {  //case 2
     67                     
     68                     node = node.getParent();
     69                     leftRotate(node);
     70                     
     71                 } else {                                          //case 3
     72                     
     73                     node.getParent().setColor(Color.BLACK);
     74                     node.getParent().getParent().setColor(Color.RED);
     75                     
     76                     rightRotate(node.getParent().getParent());
     77                     
     78                 }
     79                                 
     80             } else {
     81                 
     82                 Node leftNuncle = node.getParent().getParent().getLeft();
     83                 
     84                 if (leftNuncle.getColor() == Color.RED) {     //case 4
     85                     
     86                     leftNuncle.setColor(Color.BLACK);
     87                     node.getParent().setColor(Color.BLACK);
     88                     node.getParent().getParent().setColor(Color.RED);
     89                     node = node.getParent().getParent();
     90                 
     91                 } else if (node == node.getParent().getLeft()) { //case 5
     92                 
     93                     node = node.getParent();
     94                     rightRotate(node);
     95                                         
     96                 } else {                                          // case 6
     97                     
     98                     node.getParent().setColor(Color.BLACK);
     99                     node.getParent().getParent().setColor(Color.RED);
    100                     leftRotate(node.getParent().getParent());
    101                             
    102                 }
    103                                 
    104             }
    105             
    106             
    107         }
    108         
    109         root.setColor(Color.BLACK);
    110         
    111     }
    112     
    113     
    114     //删除节点
    115     public Node rbDelete(int data) {
    116         
    117         Node node = search(data);
    118         Node temp = NIL;
    119         Node child = NIL;
    120         if (node == null) {
    121             return null;
    122         } else {
    123             if (node.getLeft() == NIL || node.getRight() == NIL) {
    124                 temp = node;            
    125             } else {
    126                 temp = successor(node);
    127             }
    128             
    129             if (temp.getLeft() != NIL) {
    130                 child = temp.getLeft();
    131             } else {
    132                 child = temp.getRight();
    133             }
    134             
    135             child.setParent(temp.getParent());
    136             
    137             if (temp.getParent() == NIL) {
    138                 root = child;
    139             } else if (temp == temp.getParent().getLeft()) {
    140                 temp.getParent().setLeft(child);
    141             } else {
    142                 temp.getParent().setRight(child);
    143             }
    144             
    145             if (temp != node) {
    146                 node.setValue(temp.getValue());
    147             }
    148             
    149             if (temp.getColor() == Color.BLACK) {
    150                 rb_Delete_Fixup(child);
    151             }
    152             return temp;
    153         }
    154         
    155         
    156         
    157         
    158     }
    159     
    160     //删除节点后的调整
    161     private void rb_Delete_Fixup(Node node) {
    162         
    163         while (node != root && node.getColor() == Color.BLACK) {
    164             
    165             if (node == node.getParent().getLeft()) {
    166                 
    167                 Node rightBrother = node.getParent().getRight();
    168                 if (rightBrother.getColor() == Color.RED) {          //case 1 node节点为左孩子,node节点的兄弟为RED
    169                     rightBrother.setColor(Color.BLACK);
    170                     node.getParent().setColor(Color.RED);
    171                     leftRotate(node.getParent());
    172                     rightBrother = node.getParent().getRight();
    173                 }
    174                 
    175                 if (rightBrother.getLeft().getColor() == Color.BLACK && rightBrother.getRight().getColor() == Color.BLACK) {
    176                     rightBrother.setColor(Color.RED);
    177                     node = node.getParent();
    178                 } else if (rightBrother.getRight().getColor() == Color.BLACK) {
    179                     rightBrother.getLeft().setColor(Color.BLACK);
    180                     rightBrother.setColor(Color.RED);
    181                     rightRotate(rightBrother);
    182                     rightBrother = node.getParent().getRight();
    183                 } else {
    184                     rightBrother.setColor(node.getParent().getColor());
    185                     node.getParent().setColor(Color.BLACK);
    186                     rightBrother.getRight().setColor(Color.BLACK);
    187                     leftRotate(node.getParent());
    188                     node = root;
    189                 }
    190                 
    191                 
    192             } else {
    193                 
    194                 Node leftBrother = node.getParent().getLeft();
    195                 if (leftBrother.getColor() == Color.RED) {
    196                     leftBrother.setColor(Color.BLACK);
    197                     node.getParent().setColor(Color.RED);
    198                     rightRotate(node.getParent());
    199                     leftBrother = node.getParent().getLeft();
    200                 } 
    201                 
    202                 if (leftBrother.getLeft().getColor() == Color.BLACK && leftBrother.getRight().getColor() == Color.BLACK) {
    203                     leftBrother.setColor(Color.RED);
    204                     node = node.getParent();
    205                                                     
    206                 } else if (leftBrother.getLeft().getColor() == Color.BLACK) {
    207                     
    208                     leftBrother.setColor(Color.RED);
    209                     leftBrother.getRight().setColor(Color.BLACK);
    210                     leftRotate(leftBrother);
    211                     leftBrother = node.getParent().getLeft();
    212                     
    213                 } else {
    214                     
    215                     leftBrother.setColor(node.getParent().getColor());
    216                     node.getParent().setColor(Color.BLACK);
    217                     leftBrother.getLeft().setColor(Color.BLACK);
    218                     rightRotate(node.getParent());
    219                     node = root;
    220                                                             
    221                 }
    222                                 
    223             }
    224                     
    225         }
    226             
    227         node.setColor(Color.BLACK);
    228     }
    229     
    230     
    231     //查找节点node的后继节点
    232 
    233     public Node successor(Node node) {
    234         
    235         Node rightChild = node.getRight();
    236         if  (rightChild != NIL) {
    237             Node previous = null;
    238             while (rightChild != NIL) {
    239                 previous = rightChild;
    240                 rightChild = rightChild.getLeft();
    241             }
    242             return previous;
    243         } else {
    244             
    245             Node parent = node.getParent();
    246             while (parent != NIL && node != parent.getLeft()) {
    247                 node = parent;
    248                 parent = parent.getParent();
    249             }
    250             
    251             return parent;
    252                         
    253         }
    254 
    255     }
    256     
    257     
    258     //查找节点
    259     public Node search(int data) {
    260         Node temp = root;
    261         
    262         while (temp != NIL) {
    263             if (temp.getValue() == data) {
    264                 return temp;
    265             } else  if (data < temp.getValue()) {
    266                 temp = temp.getLeft();
    267             } else {
    268                 temp = temp.getRight();
    269             }
    270         }
    271         return null;
    272     }
    273     
    274     
    275     
    276     
    277     //左转函数
    278     private void leftRotate(Node node) {
    279         
    280         Node rightNode = node.getRight();
    281         
    282         node.setRight(rightNode.getLeft());
    283         if (rightNode.getLeft() != NIL) {
    284             rightNode.getLeft().setParent(node);
    285         }
    286         rightNode.setParent(node.getParent());
    287         
    288         if (node.getParent() == NIL) {
    289             rightNode = root;
    290         } else if (node == node.getParent().getLeft()) {
    291             node.getParent().setLeft(rightNode);
    292         } else {
    293             node.getParent().setRight(rightNode);
    294         }
    295         
    296         rightNode.setLeft(node);
    297         node.setParent(rightNode);
    298         
    299         
    300     }
    301     
    302     //右转函数
    303     private void rightRotate(Node node) {
    304         
    305         Node leftNode = node.getLeft();
    306         node.setLeft(leftNode.getRight());
    307         
    308         if (leftNode.getRight() != null) {
    309             leftNode.getRight().setParent(node);
    310         }
    311         
    312         leftNode.setParent(node.getParent());
    313         
    314         if (node.getParent() == NIL) {
    315             root = leftNode;
    316         } else if (node == node.getParent().getLeft()) {
    317             node.getParent().setLeft(leftNode);
    318         } else {
    319             node.getParent().setRight(leftNode);
    320         }
    321         
    322         leftNode.setRight(node);
    323         node.setParent(leftNode);
    324                     
    325     }
    326     
    327     //中序遍历红黑树
    328     public void printTree() {
    329         inOrderTraverse(root);
    330     }
    331     
    332     private void inOrderTraverse(Node node) {
    333         
    334         if (node != NIL) {
    335             inOrderTraverse(node.getLeft());
    336             System.out.println(" 节点:"+node.getValue() + "的颜色为:" + node.getColor());
    337             inOrderTraverse(node.getRight());
    338         }
    339         
    340     }
    341     
    342     
    343     public Node getNIL() {
    344         return NIL;
    345     }
    346 
    347 }
    348 
    349 
    350 
    351 class Node {
    352     private Node left;
    353     private Node right;
    354     private Node parent;
    355     private Color color;
    356     private int value;
    357     
    358     public Node() {
    359     }
    360     
    361     public Node(Node left, Node right, Node parent, Color color, int value) {
    362         super();
    363         this.left = left;
    364         this.right = right;
    365         this.parent = parent;
    366         this.color = color;
    367         this.value = value;
    368     }
    369     
    370     public Node(int value) {
    371         this(null,null,null,null,value);
    372     }
    373 
    374     public Node getLeft() {
    375         return left;
    376     }
    377 
    378     public void setLeft(Node left) {
    379         this.left = left;
    380     }
    381 
    382     public Node getRight() {
    383         return right;
    384     }
    385 
    386     public void setRight(Node right) {
    387         this.right = right;
    388     }
    389 
    390     public Node getParent() {
    391         return parent;
    392     }
    393 
    394     public void setParent(Node parent) {
    395         this.parent = parent;
    396     }
    397 
    398     public Color getColor() {
    399         return color;
    400     }
    401 
    402     public void setColor(Color color) {
    403         this.color = color;
    404     }
    405 
    406     public int getValue() {
    407         return value;
    408     }
    409 
    410     public void setValue(int value) {
    411         this.value = value;
    412     }
    413     
    414 }
    415 enum Color {
    416     RED,BLACK
    417 }
    View Code

     红黑树的动态演示:

    http://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html

  • 相关阅读:
    webServer xampp的安装及使用
    javascript 原生方法监听DOM结构改变事件
    c# 文件简繁体转换
    c# 网络是否连接
    JMS
    JMS
    JMS
    Quartz Scheduler(2.2.1)
    MySQL
    Git CMD
  • 原文地址:https://www.cnblogs.com/tonyluis/p/5713943.html
Copyright © 2011-2022 走看看