src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/RBTree.java
author pliden
Fri, 14 Sep 2018 14:44:11 +0200
changeset 51741 ed9b1200dd81
parent 47216 71c04702a3d5
permissions -rw-r--r--
8209163: SA: Show Object Histogram asserts with ZGC Reviewed-by: ysuenaga, jcbeyler
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1
489c9b5090e2 Initial load
duke
parents:
diff changeset
     1
/*
5547
f4b087cbb361 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 1
diff changeset
     2
 * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
1
489c9b5090e2 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
489c9b5090e2 Initial load
duke
parents:
diff changeset
     4
 *
489c9b5090e2 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
489c9b5090e2 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
489c9b5090e2 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.
489c9b5090e2 Initial load
duke
parents:
diff changeset
     8
 *
489c9b5090e2 Initial load
duke
parents:
diff changeset
     9
 * This code is distributed in the hope that it will be useful, but WITHOUT
489c9b5090e2 Initial load
duke
parents:
diff changeset
    10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
489c9b5090e2 Initial load
duke
parents:
diff changeset
    11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
489c9b5090e2 Initial load
duke
parents:
diff changeset
    12
 * version 2 for more details (a copy is included in the LICENSE file that
489c9b5090e2 Initial load
duke
parents:
diff changeset
    13
 * accompanied this code).
489c9b5090e2 Initial load
duke
parents:
diff changeset
    14
 *
489c9b5090e2 Initial load
duke
parents:
diff changeset
    15
 * You should have received a copy of the GNU General Public License version
489c9b5090e2 Initial load
duke
parents:
diff changeset
    16
 * 2 along with this work; if not, write to the Free Software Foundation,
489c9b5090e2 Initial load
duke
parents:
diff changeset
    17
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
489c9b5090e2 Initial load
duke
parents:
diff changeset
    18
 *
5547
f4b087cbb361 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 1
diff changeset
    19
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
f4b087cbb361 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 1
diff changeset
    20
 * or visit www.oracle.com if you need additional information or have any
f4b087cbb361 6941466: Oracle rebranding changes for Hotspot repositories
trims
parents: 1
diff changeset
    21
 * questions.
1
489c9b5090e2 Initial load
duke
parents:
diff changeset
    22
 *
489c9b5090e2 Initial load
duke
parents:
diff changeset
    23
 */
489c9b5090e2 Initial load
duke
parents:
diff changeset
    24
489c9b5090e2 Initial load
duke
parents:
diff changeset
    25
package sun.jvm.hotspot.utilities;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    26
489c9b5090e2 Initial load
duke
parents:
diff changeset
    27
/** <P> This class implements a Red-Black tree as described in Cormen,
489c9b5090e2 Initial load
duke
parents:
diff changeset
    28
    Leiserson, Rivest, <I>Introduction to Algorithms</I>, MIT Press:
489c9b5090e2 Initial load
duke
parents:
diff changeset
    29
    Cambridge, MA, 1990. </P>
489c9b5090e2 Initial load
duke
parents:
diff changeset
    30
489c9b5090e2 Initial load
duke
parents:
diff changeset
    31
    <P> A property of this implementation is that it is designed to
489c9b5090e2 Initial load
duke
parents:
diff changeset
    32
    allow straightforward augmentation of the data structure. A valid
489c9b5090e2 Initial load
duke
parents:
diff changeset
    33
    augmentation is one in which a node contains auxiliary information
489c9b5090e2 Initial load
duke
parents:
diff changeset
    34
    that can be computed by examining only this node and its left and
489c9b5090e2 Initial load
duke
parents:
diff changeset
    35
    right children (see CLR, section 15.2). </P>
489c9b5090e2 Initial load
duke
parents:
diff changeset
    36
489c9b5090e2 Initial load
duke
parents:
diff changeset
    37
    <P> An RBTree is a structure of RBNodes, each of which contains a
489c9b5090e2 Initial load
duke
parents:
diff changeset
    38
    user data element. When the user inserts a piece of data into the
489c9b5090e2 Initial load
duke
parents:
diff changeset
    39
    tree, a new RBNode is constructed around it. </P>
489c9b5090e2 Initial load
duke
parents:
diff changeset
    40
489c9b5090e2 Initial load
duke
parents:
diff changeset
    41
    <P> An RBTree takes a Comparator as argument to its constructor
489c9b5090e2 Initial load
duke
parents:
diff changeset
    42
    which is used internally to order the nodes in the tree. The
489c9b5090e2 Initial load
duke
parents:
diff changeset
    43
    comparator's arguments are obtained by calling the routine
489c9b5090e2 Initial load
duke
parents:
diff changeset
    44
    "getNodeData" on two nodes; the default implementaion returns the
489c9b5090e2 Initial load
duke
parents:
diff changeset
    45
    node data. This Comparator is also used to perform the generic
489c9b5090e2 Initial load
duke
parents:
diff changeset
    46
    "find" operation, which returns the RBNode containing user data
489c9b5090e2 Initial load
duke
parents:
diff changeset
    47
    precisely equalling the query data. Different types of user data
489c9b5090e2 Initial load
duke
parents:
diff changeset
    48
    will typically require different types of traversals as well as
489c9b5090e2 Initial load
duke
parents:
diff changeset
    49
    additional comparison operations; these are left to the RBTree
489c9b5090e2 Initial load
duke
parents:
diff changeset
    50
    subclass. </P>
489c9b5090e2 Initial load
duke
parents:
diff changeset
    51
489c9b5090e2 Initial load
duke
parents:
diff changeset
    52
*/
489c9b5090e2 Initial load
duke
parents:
diff changeset
    53
489c9b5090e2 Initial load
duke
parents:
diff changeset
    54
import java.io.PrintStream;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    55
import java.util.Comparator;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    56
import java.util.Random;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    57
489c9b5090e2 Initial load
duke
parents:
diff changeset
    58
public class RBTree {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    59
  private RBNode root;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    60
  private Comparator comparator;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    61
  protected static final boolean DEBUGGING = true;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    62
  protected static final boolean VERBOSE   = true;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    63
  protected static final boolean REALLY_VERBOSE = false;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    64
489c9b5090e2 Initial load
duke
parents:
diff changeset
    65
  public RBTree(Comparator comparator) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    66
    this.comparator = comparator;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    67
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
    68
489c9b5090e2 Initial load
duke
parents:
diff changeset
    69
  public RBNode getRoot() {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    70
    return root;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    71
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
    72
489c9b5090e2 Initial load
duke
parents:
diff changeset
    73
  public void insertNode(RBNode x) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    74
    treeInsert(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
    75
489c9b5090e2 Initial load
duke
parents:
diff changeset
    76
    x.setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
    77
    boolean shouldPropagate = x.update();
489c9b5090e2 Initial load
duke
parents:
diff changeset
    78
489c9b5090e2 Initial load
duke
parents:
diff changeset
    79
    if (DEBUGGING && REALLY_VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    80
      System.err.println("RBTree.insertNode");
489c9b5090e2 Initial load
duke
parents:
diff changeset
    81
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
    82
489c9b5090e2 Initial load
duke
parents:
diff changeset
    83
    RBNode propagateStart = x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
    84
489c9b5090e2 Initial load
duke
parents:
diff changeset
    85
    // Loop invariant: x has been updated.
489c9b5090e2 Initial load
duke
parents:
diff changeset
    86
    while ((x != root) && (x.getParent().getColor() == RBColor.RED)) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    87
      if (x.getParent() == x.getParent().getParent().getLeft()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    88
        RBNode y = x.getParent().getParent().getRight();
489c9b5090e2 Initial load
duke
parents:
diff changeset
    89
        if ((y != null) && (y.getColor() == RBColor.RED)) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    90
          // Case 1
489c9b5090e2 Initial load
duke
parents:
diff changeset
    91
          if (DEBUGGING && REALLY_VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
    92
            System.err.println("  Case 1/1");
489c9b5090e2 Initial load
duke
parents:
diff changeset
    93
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
    94
          x.getParent().setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
    95
          y.setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
    96
          x.getParent().getParent().setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
    97
          x.getParent().update();
489c9b5090e2 Initial load
duke
parents:
diff changeset
    98
          x = x.getParent().getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
    99
          shouldPropagate = x.update();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   100
          propagateStart = x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   101
        } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   102
          if (x == x.getParent().getRight()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   103
            // Case 2
489c9b5090e2 Initial load
duke
parents:
diff changeset
   104
            if (DEBUGGING && REALLY_VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   105
              System.err.println("  Case 1/2");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   106
            }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   107
            x = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   108
            leftRotate(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   109
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   110
          // Case 3
489c9b5090e2 Initial load
duke
parents:
diff changeset
   111
          if (DEBUGGING && REALLY_VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   112
            System.err.println("  Case 1/3");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   113
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   114
          x.getParent().setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   115
          x.getParent().getParent().setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   116
          shouldPropagate = rightRotate(x.getParent().getParent());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   117
          propagateStart = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   118
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   119
      } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   120
        // Same as then clause with "right" and "left" exchanged
489c9b5090e2 Initial load
duke
parents:
diff changeset
   121
        RBNode y = x.getParent().getParent().getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   122
        if ((y != null) && (y.getColor() == RBColor.RED)) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   123
          // Case 1
489c9b5090e2 Initial load
duke
parents:
diff changeset
   124
          if (DEBUGGING && REALLY_VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   125
            System.err.println("  Case 2/1");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   126
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   127
          x.getParent().setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   128
          y.setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   129
          x.getParent().getParent().setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   130
          x.getParent().update();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   131
          x = x.getParent().getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   132
          shouldPropagate = x.update();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   133
          propagateStart = x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   134
        } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   135
          if (x == x.getParent().getLeft()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   136
            // Case 2
489c9b5090e2 Initial load
duke
parents:
diff changeset
   137
            if (DEBUGGING && REALLY_VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   138
              System.err.println("  Case 2/2");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   139
            }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   140
            x = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   141
            rightRotate(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   142
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   143
          // Case 3
489c9b5090e2 Initial load
duke
parents:
diff changeset
   144
          if (DEBUGGING && REALLY_VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   145
            System.err.println("  Case 2/3");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   146
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   147
          x.getParent().setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   148
          x.getParent().getParent().setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   149
          shouldPropagate = leftRotate(x.getParent().getParent());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   150
          propagateStart = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   151
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   152
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   153
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   154
489c9b5090e2 Initial load
duke
parents:
diff changeset
   155
    while (shouldPropagate && (propagateStart != root)) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   156
      if (DEBUGGING && REALLY_VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   157
        System.err.println("  Propagating");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   158
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   159
      propagateStart = propagateStart.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   160
      shouldPropagate = propagateStart.update();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   161
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   162
489c9b5090e2 Initial load
duke
parents:
diff changeset
   163
    root.setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   164
489c9b5090e2 Initial load
duke
parents:
diff changeset
   165
    if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   166
      verify();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   167
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   168
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   169
489c9b5090e2 Initial load
duke
parents:
diff changeset
   170
  /** FIXME: this does not work properly yet for augmented red-black
489c9b5090e2 Initial load
duke
parents:
diff changeset
   171
      trees since it doesn't update nodes. Need to figure out exactly
489c9b5090e2 Initial load
duke
parents:
diff changeset
   172
      from which points we need to propagate updates upwards. */
489c9b5090e2 Initial load
duke
parents:
diff changeset
   173
  public void deleteNode(RBNode z) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   174
    // This routine splices out a node. Note that we may not actually
489c9b5090e2 Initial load
duke
parents:
diff changeset
   175
    // delete the RBNode z from the tree, but may instead remove
489c9b5090e2 Initial load
duke
parents:
diff changeset
   176
    // another node from the tree, copying its contents into z.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   177
489c9b5090e2 Initial load
duke
parents:
diff changeset
   178
    // y is the node to be unlinked from the tree
489c9b5090e2 Initial load
duke
parents:
diff changeset
   179
    RBNode y;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   180
    if ((z.getLeft() == null) || (z.getRight() == null)) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   181
      y = z;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   182
    } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   183
      y = treeSuccessor(z);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   184
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   185
    // y is guaranteed to be non-null at this point
489c9b5090e2 Initial load
duke
parents:
diff changeset
   186
    RBNode x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   187
    if (y.getLeft() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   188
      x = y.getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   189
    } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   190
      x = y.getRight();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   191
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   192
    // x is the potential child of y to replace it in the tree.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   193
    // x may be null at this point
489c9b5090e2 Initial load
duke
parents:
diff changeset
   194
    RBNode xParent;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   195
    if (x != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   196
      x.setParent(y.getParent());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   197
      xParent = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   198
    } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   199
      xParent = y.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   200
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   201
    if (y.getParent() == null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   202
      root = x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   203
    } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   204
      if (y == y.getParent().getLeft()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   205
        y.getParent().setLeft(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   206
      } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   207
        y.getParent().setRight(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   208
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   209
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   210
    if (y != z) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   211
      z.copyFrom(y);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   212
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   213
    if (y.getColor() == RBColor.BLACK) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   214
      deleteFixup(x, xParent);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   215
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   216
489c9b5090e2 Initial load
duke
parents:
diff changeset
   217
    if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   218
      verify();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   219
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   220
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   221
489c9b5090e2 Initial load
duke
parents:
diff changeset
   222
  public void print() {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   223
    printOn(System.out);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   224
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   225
489c9b5090e2 Initial load
duke
parents:
diff changeset
   226
  public void printOn(PrintStream tty) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   227
    printFromNode(root, tty, 0);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   228
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   229
489c9b5090e2 Initial load
duke
parents:
diff changeset
   230
  //----------------------------------------------------------------------
489c9b5090e2 Initial load
duke
parents:
diff changeset
   231
  // Functionality overridable by subclass
489c9b5090e2 Initial load
duke
parents:
diff changeset
   232
  //
489c9b5090e2 Initial load
duke
parents:
diff changeset
   233
489c9b5090e2 Initial load
duke
parents:
diff changeset
   234
  protected Object getNodeValue(RBNode node) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   235
    return node.getData();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   236
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   237
489c9b5090e2 Initial load
duke
parents:
diff changeset
   238
  /** Verify invariants are preserved */
489c9b5090e2 Initial load
duke
parents:
diff changeset
   239
  protected void verify() {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   240
    verifyFromNode(root);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   241
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   242
489c9b5090e2 Initial load
duke
parents:
diff changeset
   243
  //----------------------------------------------------------------------
489c9b5090e2 Initial load
duke
parents:
diff changeset
   244
  // Internals only below this point
489c9b5090e2 Initial load
duke
parents:
diff changeset
   245
  //
489c9b5090e2 Initial load
duke
parents:
diff changeset
   246
489c9b5090e2 Initial load
duke
parents:
diff changeset
   247
  //
489c9b5090e2 Initial load
duke
parents:
diff changeset
   248
  // Vanilla binary search tree operations
489c9b5090e2 Initial load
duke
parents:
diff changeset
   249
  //
489c9b5090e2 Initial load
duke
parents:
diff changeset
   250
489c9b5090e2 Initial load
duke
parents:
diff changeset
   251
  private void treeInsert(RBNode z) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   252
    RBNode y = null;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   253
    RBNode x = root;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   254
489c9b5090e2 Initial load
duke
parents:
diff changeset
   255
    while (x != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   256
      y = x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   257
      if (comparator.compare(getNodeValue(z), getNodeValue(x)) < 0) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   258
        x = x.getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   259
      } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   260
        x = x.getRight();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   261
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   262
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   263
    z.setParent(y);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   264
    if (y == null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   265
      root = z;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   266
    } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   267
      if (comparator.compare(getNodeValue(z), getNodeValue(y)) < 0) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   268
        y.setLeft(z);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   269
      } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   270
        y.setRight(z);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   271
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   272
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   273
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   274
489c9b5090e2 Initial load
duke
parents:
diff changeset
   275
  private RBNode treeSuccessor(RBNode x) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   276
    if (x.getRight() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   277
      return treeMinimum(x.getRight());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   278
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   279
    RBNode y = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   280
    while ((y != null) && (x == y.getRight())) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   281
      x = y;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   282
      y = y.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   283
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   284
    return y;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   285
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   286
489c9b5090e2 Initial load
duke
parents:
diff changeset
   287
  private RBNode treeMinimum(RBNode x) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   288
    while (x.getLeft() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   289
      x = x.getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   290
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   291
    return x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   292
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   293
489c9b5090e2 Initial load
duke
parents:
diff changeset
   294
  //
489c9b5090e2 Initial load
duke
parents:
diff changeset
   295
  // Insertion and deletion helpers
489c9b5090e2 Initial load
duke
parents:
diff changeset
   296
  //
489c9b5090e2 Initial load
duke
parents:
diff changeset
   297
489c9b5090e2 Initial load
duke
parents:
diff changeset
   298
  /** Returns true if updates must continue propagating up the tree */
489c9b5090e2 Initial load
duke
parents:
diff changeset
   299
  private boolean leftRotate(RBNode x) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   300
    // Set y.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   301
    RBNode y = x.getRight();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   302
    // Turn y's left subtree into x's right subtree.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   303
    x.setRight(y.getLeft());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   304
    if (y.getLeft() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   305
      y.getLeft().setParent(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   306
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   307
    // Link x's parent to y.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   308
    y.setParent(x.getParent());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   309
    if (x.getParent() == null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   310
      root = y;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   311
    } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   312
      if (x == x.getParent().getLeft()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   313
        x.getParent().setLeft(y);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   314
      } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   315
        x.getParent().setRight(y);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   316
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   317
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   318
    // Put x on y's left.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   319
    y.setLeft(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   320
    x.setParent(y);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   321
    // Update nodes in appropriate order (lowest to highest)
489c9b5090e2 Initial load
duke
parents:
diff changeset
   322
    boolean res = x.update();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   323
    res = y.update() || res;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   324
    return res;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   325
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   326
489c9b5090e2 Initial load
duke
parents:
diff changeset
   327
  /** Returns true if updates must continue propagating up the tree */
489c9b5090e2 Initial load
duke
parents:
diff changeset
   328
  private boolean rightRotate(RBNode y) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   329
    // Set x.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   330
    RBNode x = y.getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   331
    // Turn x's right subtree into y's left subtree.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   332
    y.setLeft(x.getRight());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   333
    if (x.getRight() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   334
      x.getRight().setParent(y);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   335
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   336
    // Link y's parent into x.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   337
    x.setParent(y.getParent());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   338
    if (y.getParent() == null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   339
      root = x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   340
    } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   341
      if (y == y.getParent().getLeft()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   342
        y.getParent().setLeft(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   343
      } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   344
        y.getParent().setRight(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   345
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   346
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   347
    // Put y on x's right.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   348
    x.setRight(y);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   349
    y.setParent(x);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   350
    // Update nodes in appropriate order (lowest to highest)
489c9b5090e2 Initial load
duke
parents:
diff changeset
   351
    boolean res = y.update();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   352
    res = x.update() || res;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   353
    return res;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   354
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   355
489c9b5090e2 Initial load
duke
parents:
diff changeset
   356
  /** Restores red-black property to tree after splicing out node
489c9b5090e2 Initial load
duke
parents:
diff changeset
   357
      during deletion. Note that x may be null, which is why xParent
489c9b5090e2 Initial load
duke
parents:
diff changeset
   358
      must be specified. */
489c9b5090e2 Initial load
duke
parents:
diff changeset
   359
  private void deleteFixup(RBNode x, RBNode xParent) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   360
    while ((x != root) && ((x == null) || (x.getColor() == RBColor.BLACK))) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   361
      if (x == xParent.getLeft()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   362
        // NOTE: the text points out that w can not be null. The
489c9b5090e2 Initial load
duke
parents:
diff changeset
   363
        // reason is not obvious from simply examining the code; it
489c9b5090e2 Initial load
duke
parents:
diff changeset
   364
        // comes about because of properties of the red-black tree.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   365
        RBNode w = xParent.getRight();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   366
        if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   367
          if (w == null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   368
            throw new RuntimeException("x's sibling should not be null");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   369
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   370
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   371
        if (w.getColor() == RBColor.RED) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   372
          // Case 1
489c9b5090e2 Initial load
duke
parents:
diff changeset
   373
          w.setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   374
          xParent.setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   375
          leftRotate(xParent);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   376
          w = xParent.getRight();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   377
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   378
        if (((w.getLeft()  == null) || (w.getLeft().getColor()  == RBColor.BLACK)) &&
489c9b5090e2 Initial load
duke
parents:
diff changeset
   379
            ((w.getRight() == null) || (w.getRight().getColor() == RBColor.BLACK))) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   380
          // Case 2
489c9b5090e2 Initial load
duke
parents:
diff changeset
   381
          w.setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   382
          x = xParent;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   383
          xParent = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   384
        } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   385
          if ((w.getRight() == null) || (w.getRight().getColor() == RBColor.BLACK)) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   386
            // Case 3
489c9b5090e2 Initial load
duke
parents:
diff changeset
   387
            w.getLeft().setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   388
            w.setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   389
            rightRotate(w);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   390
            w = xParent.getRight();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   391
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   392
          // Case 4
489c9b5090e2 Initial load
duke
parents:
diff changeset
   393
          w.setColor(xParent.getColor());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   394
          xParent.setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   395
          if (w.getRight() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   396
            w.getRight().setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   397
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   398
          leftRotate(xParent);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   399
          x = root;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   400
          xParent = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   401
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   402
      } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   403
        // Same as clause above with "right" and "left"
489c9b5090e2 Initial load
duke
parents:
diff changeset
   404
        // exchanged
489c9b5090e2 Initial load
duke
parents:
diff changeset
   405
489c9b5090e2 Initial load
duke
parents:
diff changeset
   406
        // NOTE: the text points out that w can not be null. The
489c9b5090e2 Initial load
duke
parents:
diff changeset
   407
        // reason is not obvious from simply examining the code; it
489c9b5090e2 Initial load
duke
parents:
diff changeset
   408
        // comes about because of properties of the red-black tree.
489c9b5090e2 Initial load
duke
parents:
diff changeset
   409
        RBNode w = xParent.getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   410
        if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   411
          if (w == null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   412
            throw new RuntimeException("x's sibling should not be null");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   413
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   414
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   415
        if (w.getColor() == RBColor.RED) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   416
          // Case 1
489c9b5090e2 Initial load
duke
parents:
diff changeset
   417
          w.setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   418
          xParent.setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   419
          rightRotate(xParent);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   420
          w = xParent.getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   421
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   422
        if (((w.getRight() == null) || (w.getRight().getColor() == RBColor.BLACK)) &&
489c9b5090e2 Initial load
duke
parents:
diff changeset
   423
            ((w.getLeft()  == null) || (w.getLeft().getColor()  == RBColor.BLACK))) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   424
          // Case 2
489c9b5090e2 Initial load
duke
parents:
diff changeset
   425
          w.setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   426
          x = xParent;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   427
          xParent = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   428
        } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   429
          if ((w.getLeft() == null) || (w.getLeft().getColor() == RBColor.BLACK)) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   430
            // Case 3
489c9b5090e2 Initial load
duke
parents:
diff changeset
   431
            w.getRight().setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   432
            w.setColor(RBColor.RED);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   433
            leftRotate(w);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   434
            w = xParent.getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   435
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   436
          // Case 4
489c9b5090e2 Initial load
duke
parents:
diff changeset
   437
          w.setColor(xParent.getColor());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   438
          xParent.setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   439
          if (w.getLeft() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   440
            w.getLeft().setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   441
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   442
          rightRotate(xParent);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   443
          x = root;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   444
          xParent = x.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   445
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   446
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   447
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   448
    if (x != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   449
      x.setColor(RBColor.BLACK);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   450
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   451
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   452
489c9b5090e2 Initial load
duke
parents:
diff changeset
   453
  // Returns the number of black children along all paths to all
489c9b5090e2 Initial load
duke
parents:
diff changeset
   454
  // leaves of the given node
489c9b5090e2 Initial load
duke
parents:
diff changeset
   455
  private int verifyFromNode(RBNode node) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   456
    // Bottoms out at leaf nodes
489c9b5090e2 Initial load
duke
parents:
diff changeset
   457
    if (node == null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   458
      return 1;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   459
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   460
489c9b5090e2 Initial load
duke
parents:
diff changeset
   461
    // Each node is either red or black
489c9b5090e2 Initial load
duke
parents:
diff changeset
   462
    if (!((node.getColor() == RBColor.RED) ||
489c9b5090e2 Initial load
duke
parents:
diff changeset
   463
          (node.getColor() == RBColor.BLACK))) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   464
      if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   465
        System.err.println("Verify failed:");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   466
        printOn(System.err);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   467
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   468
      throw new RuntimeException("Verify failed (1)");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   469
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   470
489c9b5090e2 Initial load
duke
parents:
diff changeset
   471
    // Every leaf (null) is black
489c9b5090e2 Initial load
duke
parents:
diff changeset
   472
489c9b5090e2 Initial load
duke
parents:
diff changeset
   473
    if (node.getColor() == RBColor.RED) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   474
      // Both its children are black
489c9b5090e2 Initial load
duke
parents:
diff changeset
   475
      if (node.getLeft() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   476
        if (node.getLeft().getColor() != RBColor.BLACK) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   477
          if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   478
            System.err.println("Verify failed:");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   479
            printOn(System.err);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   480
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   481
          throw new RuntimeException("Verify failed (2)");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   482
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   483
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   484
      if (node.getRight() != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   485
        if (node.getRight().getColor() != RBColor.BLACK) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   486
          if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   487
            System.err.println("Verify failed:");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   488
            printOn(System.err);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   489
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   490
          throw new RuntimeException("Verify failed (3)");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   491
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   492
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   493
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   494
489c9b5090e2 Initial load
duke
parents:
diff changeset
   495
    // Every simple path to a leaf contains the same number of black
489c9b5090e2 Initial load
duke
parents:
diff changeset
   496
    // nodes
489c9b5090e2 Initial load
duke
parents:
diff changeset
   497
    int i = verifyFromNode(node.getLeft());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   498
    int j = verifyFromNode(node.getRight());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   499
    if (i != j) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   500
      if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   501
        System.err.println("Verify failed:");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   502
        printOn(System.err);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   503
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   504
      throw new RuntimeException("Verify failed (4) (left black count = " +
489c9b5090e2 Initial load
duke
parents:
diff changeset
   505
                                 i + ", right black count = " + j + ")");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   506
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   507
489c9b5090e2 Initial load
duke
parents:
diff changeset
   508
    return i + ((node.getColor() == RBColor.RED) ? 0 : 1);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   509
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   510
489c9b5090e2 Initial load
duke
parents:
diff changeset
   511
  /** Debugging */
489c9b5090e2 Initial load
duke
parents:
diff changeset
   512
  private void printFromNode(RBNode node, PrintStream tty, int indentDepth) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   513
    for (int i = 0; i < indentDepth; i++) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   514
      tty.print(" ");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   515
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   516
489c9b5090e2 Initial load
duke
parents:
diff changeset
   517
    tty.print("-");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   518
    if (node == null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   519
      tty.println();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   520
      return;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   521
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   522
489c9b5090e2 Initial load
duke
parents:
diff changeset
   523
    tty.println(" " + getNodeValue(node) +
489c9b5090e2 Initial load
duke
parents:
diff changeset
   524
                ((node.getColor() == RBColor.RED) ? " (red)" : " (black)"));
489c9b5090e2 Initial load
duke
parents:
diff changeset
   525
    printFromNode(node.getLeft(), tty, indentDepth + 2);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   526
    printFromNode(node.getRight(), tty, indentDepth + 2);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   527
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   528
489c9b5090e2 Initial load
duke
parents:
diff changeset
   529
  //----------------------------------------------------------------------
489c9b5090e2 Initial load
duke
parents:
diff changeset
   530
  // Test harness
489c9b5090e2 Initial load
duke
parents:
diff changeset
   531
  //
489c9b5090e2 Initial load
duke
parents:
diff changeset
   532
489c9b5090e2 Initial load
duke
parents:
diff changeset
   533
  public static void main(String[] args) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   534
    int treeSize = 10000;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   535
    int maxVal = treeSize;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   536
    System.err.println("Building tree...");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   537
    RBTree tree = new RBTree(new Comparator() {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   538
        public int compare(Object o1, Object o2) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   539
          Integer i1 = (Integer) o1;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   540
          Integer i2 = (Integer) o2;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   541
          if (i1.intValue() < i2.intValue()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   542
            return -1;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   543
          } else if (i1.intValue() == i2.intValue()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   544
            return 0;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   545
          }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   546
          return 1;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   547
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   548
      });
489c9b5090e2 Initial load
duke
parents:
diff changeset
   549
    Random rand = new Random(System.currentTimeMillis());
489c9b5090e2 Initial load
duke
parents:
diff changeset
   550
    for (int i = 0; i < treeSize; i++) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   551
      Integer val = new Integer(rand.nextInt(maxVal) + 1);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   552
      try {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   553
        tree.insertNode(new RBNode(val));
489c9b5090e2 Initial load
duke
parents:
diff changeset
   554
        if ((i > 0) && (i % 100 == 0)) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   555
          System.err.print(i + "...");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   556
          System.err.flush();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   557
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   558
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   559
      catch (Exception e) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   560
        e.printStackTrace();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   561
        System.err.println("While inserting value " + val);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   562
        tree.printOn(System.err);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   563
        System.exit(1);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   564
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   565
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   566
    // Now churn data in tree by deleting and inserting lots of nodes
489c9b5090e2 Initial load
duke
parents:
diff changeset
   567
    System.err.println();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   568
    System.err.println("Churning tree...");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   569
    for (int i = 0; i < treeSize; i++) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   570
      if (DEBUGGING && VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   571
        System.err.println("Iteration " + i + ":");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   572
        tree.printOn(System.err);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   573
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   574
      // Pick a random value to remove (NOTE that this is not
489c9b5090e2 Initial load
duke
parents:
diff changeset
   575
      // uniformly distributed)
489c9b5090e2 Initial load
duke
parents:
diff changeset
   576
      RBNode xParent = null;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   577
      RBNode x = tree.getRoot();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   578
      int depth = 0;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   579
      while (x != null) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   580
        // Traverse path down to leaf
489c9b5090e2 Initial load
duke
parents:
diff changeset
   581
        xParent = x;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   582
        if (rand.nextBoolean()) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   583
          x = x.getLeft();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   584
        } else {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   585
          x = x.getRight();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   586
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   587
        ++depth;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   588
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   589
      // Pick a random height at which to remove value
489c9b5090e2 Initial load
duke
parents:
diff changeset
   590
      int height = rand.nextInt(depth);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   591
      if (DEBUGGING) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   592
        if (height >= depth) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   593
          throw new RuntimeException("bug in java.util.Random");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   594
        }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   595
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   596
      // Walk that far back up (FIXME: off by one?)
489c9b5090e2 Initial load
duke
parents:
diff changeset
   597
      while (height > 0) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   598
        xParent = xParent.getParent();
489c9b5090e2 Initial load
duke
parents:
diff changeset
   599
        --height;
489c9b5090e2 Initial load
duke
parents:
diff changeset
   600
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   601
      // Tell the tree to remove this node
489c9b5090e2 Initial load
duke
parents:
diff changeset
   602
      if (DEBUGGING && VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   603
        System.err.println("(Removing value " + tree.getNodeValue(xParent) + ")");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   604
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   605
      tree.deleteNode(xParent);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   606
489c9b5090e2 Initial load
duke
parents:
diff changeset
   607
      // Now create and insert a new value
489c9b5090e2 Initial load
duke
parents:
diff changeset
   608
      Integer newVal = new Integer(rand.nextInt(maxVal) + 1);
489c9b5090e2 Initial load
duke
parents:
diff changeset
   609
      if (DEBUGGING && VERBOSE) {
489c9b5090e2 Initial load
duke
parents:
diff changeset
   610
        System.err.println("(Inserting value " + newVal + ")");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   611
      }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   612
      tree.insertNode(new RBNode(newVal));
489c9b5090e2 Initial load
duke
parents:
diff changeset
   613
    }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   614
    System.err.println("All tests passed.");
489c9b5090e2 Initial load
duke
parents:
diff changeset
   615
  }
489c9b5090e2 Initial load
duke
parents:
diff changeset
   616
}