c3b33c0631
Reviewed-by: thartmann, neliasso
646 lines
22 KiB
Java
646 lines
22 KiB
Java
/*
|
|
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package jit.graph;
|
|
|
|
// This class defines the tree object.
|
|
public class RBTree {
|
|
public final static int maxNodes = 70; // maximum nodes allowed.
|
|
public final static int INSERT = 0; // constants indicating
|
|
public final static int DELETE = 1; // the current operation
|
|
public final static int NOP = 2;
|
|
public final static Node treeNull = new Node(); // the tree NULL node.
|
|
|
|
private Node root;
|
|
private int num_of_nodes;
|
|
private int height; // The tree height, it is updated
|
|
// in each operation.
|
|
|
|
// since the algorithm is executed in stages I have to remember data
|
|
// on the state.
|
|
private Node node; // The current operation is being done on it.
|
|
private int action; // The operation being performed (insert / delete)
|
|
private int stage; // The current stage of execution
|
|
|
|
// the constructor initializes the object fields.
|
|
public RBTree() {
|
|
root = treeNull;
|
|
node = treeNull;
|
|
num_of_nodes = 0;
|
|
height = 0;
|
|
action = NOP;
|
|
stage = 0;
|
|
}
|
|
|
|
// This method returns the root of the tree.
|
|
public Node getRoot() {
|
|
return root;
|
|
}
|
|
|
|
// This method returns the number of nodes in the tree.
|
|
public int getNodes() {
|
|
return num_of_nodes;
|
|
}
|
|
|
|
// This method returns the height of the tree.
|
|
public int getHeight() {
|
|
return height;
|
|
}
|
|
|
|
|
|
// This method inserts k into the Red Black Tree
|
|
public boolean RBInsert(int k) {
|
|
// checking similar to the RB_Insert method
|
|
if (action != NOP) {
|
|
System.out.println("Only one operation can be done at a time.");
|
|
return false;
|
|
}
|
|
|
|
if (num_of_nodes == maxNodes) {
|
|
System.out.println("The maximum nodes allowed is already reached.");
|
|
return false;
|
|
}
|
|
|
|
// Check if there is already node with key k.
|
|
if (Search(k) == treeNull) {
|
|
action = INSERT;
|
|
node = new Node(k);
|
|
node.setNode(Node.Left_son, treeNull);
|
|
node.setNode(Node.Right_son, treeNull);
|
|
node.setNode(Node.Parent, treeNull);
|
|
stage = 1;
|
|
// This is the loop that perform all the operation steps.
|
|
while (stage != 0) {
|
|
// perform one step
|
|
InsertStep();
|
|
// update the tree height
|
|
updateHeight();
|
|
}
|
|
// set the action to NoOPretion.
|
|
action = NOP;
|
|
return true;
|
|
} else
|
|
System.out.println("Insertion failed. This key already exist.");
|
|
return false;
|
|
}
|
|
|
|
|
|
// This method deletes the element k from the Red Black tree
|
|
public boolean RBDelete(int k) {
|
|
// checking like in RB_Delete method
|
|
if (action != NOP) {
|
|
System.out.println("Only one operation can be done at a time.");
|
|
return false;
|
|
}
|
|
node = Search(k);
|
|
// Check if there is a node with key k.
|
|
if (node != treeNull) {
|
|
action = DELETE;
|
|
stage = 1;
|
|
// this loop perform all the operation steps.
|
|
while (stage != 0) {
|
|
// perform one step
|
|
DeleteStep();
|
|
// update the tree height
|
|
updateHeight();
|
|
}
|
|
action = NOP;
|
|
return true;
|
|
} else
|
|
System.out.println("Deletion failed. This key doesn't exist.");
|
|
return false;
|
|
}
|
|
|
|
// This method performs one step in the insertion operation.
|
|
// It performs a step according to the stage variable.
|
|
// I will not explain exactly what each stage do, just that they
|
|
// divided to 4 categories:
|
|
// 1. inserting a node to the tree.
|
|
// 2. marking nodes that will be recolored.
|
|
// 3. recoloring nodes.
|
|
// 4. rotating right or left.
|
|
private void InsertStep() {
|
|
// Pr is parent, GrPr is grandparent and Un is uncle.
|
|
Node Pr, GrPr, Un;
|
|
switch (stage) {
|
|
// Inserting a node to the tree
|
|
case 1:
|
|
Tree_Insert();
|
|
break;
|
|
// mid stage that moves the algorithm to the proper next stage
|
|
case 2:
|
|
Pr = node.getNode(Node.Parent);
|
|
GrPr = Pr.getNode(Node.Parent);
|
|
if (Pr == GrPr.getNode(Node.Left_son)) {
|
|
Un = GrPr.getNode(Node.Right_son);
|
|
if (Un.getColor() == Node.Red) {
|
|
stage = 3;
|
|
} else if (node == Pr.getNode(Node.Right_son)) {
|
|
node = Pr;
|
|
stage = 5;
|
|
} else {
|
|
stage = 6;
|
|
}
|
|
} else {
|
|
Un = GrPr.getNode(Node.Left_son);
|
|
if (Un.getColor() == Node.Red) {
|
|
stage = 3;
|
|
} else if (node == Pr.getNode(Node.Left_son)) {
|
|
node = Pr;
|
|
stage = 5;
|
|
} else {
|
|
stage = 6;
|
|
}
|
|
}
|
|
break;
|
|
// This stage marks node that will be recolored
|
|
case 3:
|
|
Pr = node.getNode(Node.Parent);
|
|
GrPr = Pr.getNode(Node.Parent);
|
|
if (Pr == GrPr.getNode(Node.Left_son)) {
|
|
Un = GrPr.getNode(Node.Right_son);
|
|
} else {
|
|
Un = GrPr.getNode(Node.Left_son);
|
|
}
|
|
node = GrPr;
|
|
stage = 4;
|
|
break;
|
|
// This stage recolors marked nodes.
|
|
case 4:
|
|
node.setColor(Node.Red);
|
|
node.getNode(Node.Left_son).setColor(Node.Black);
|
|
node.getNode(Node.Right_son).setColor(Node.Black);
|
|
|
|
if ((node == root) ||
|
|
(node.getNode(Node.Parent).getColor() == Node.Black)) {
|
|
if (root.getColor() == Node.Red) {
|
|
stage = 9;
|
|
} else
|
|
stage = 0;
|
|
} else {
|
|
stage = 2;
|
|
InsertStep();
|
|
}
|
|
break;
|
|
// This stage performs rotation operation
|
|
case 5:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Left_Rotate(node);
|
|
} else {
|
|
Right_Rotate(node);
|
|
}
|
|
stage = 6;
|
|
break;
|
|
// This stage marks nodes that will be recolor.
|
|
case 6:
|
|
Pr = node.getNode(Node.Parent);
|
|
GrPr = Pr.getNode(Node.Parent);
|
|
|
|
stage = 7;
|
|
break;
|
|
// This stage recolors marked nodes.
|
|
case 7:
|
|
Pr = node.getNode(Node.Parent);
|
|
Pr.setColor(Node.Black);
|
|
GrPr = Pr.getNode(Node.Parent);
|
|
GrPr.setColor(Node.Red);
|
|
|
|
stage = 8;
|
|
break;
|
|
// This stage performs rotation operation
|
|
case 8:
|
|
Pr = node.getNode(Node.Parent);
|
|
GrPr = Pr.getNode(Node.Parent);
|
|
if (Pr == GrPr.getNode(Node.Left_son)) {
|
|
Right_Rotate(GrPr);
|
|
} else {
|
|
Left_Rotate(GrPr);
|
|
}
|
|
if (root.getColor() == Node.Red) {
|
|
stage = 9;
|
|
} else
|
|
stage = 0;
|
|
break;
|
|
// this stage marks the root.
|
|
case 9:
|
|
stage = 10;
|
|
break;
|
|
// This stage recolors the root.
|
|
case 10:
|
|
root.setColor(Node.Black);
|
|
stage = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// This method performs one step in the deletion operation.
|
|
// It perform sa step according to the stage variable.
|
|
// I will explain exactly what each stage do, just that they
|
|
// divided to 4 categories:
|
|
// 1. deleting a node from the tree.
|
|
// 2. marking nodes that will be recolored.
|
|
// 3. recoloring nodes.
|
|
// 4. rotating right or left.
|
|
public void DeleteStep() {
|
|
// Pr is Parent, Br is Brother
|
|
Node Pr, Br;
|
|
switch (stage) {
|
|
// This stage delete a node from the tree.
|
|
case 1:
|
|
Tree_Delete();
|
|
break;
|
|
// This stage marks a nodes that will be recolored or perform other stage.
|
|
case 2:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
}
|
|
if (Br.getColor() == Node.Red) {
|
|
stage = 3;
|
|
} else if ((Br.getNode(Node.Right_son).getColor() == Node.Black)
|
|
&& (Br.getNode(Node.Left_son).getColor() == Node.Black)) {
|
|
stage = 5;
|
|
DeleteStep();
|
|
} else {
|
|
stage = 7;
|
|
DeleteStep();
|
|
}
|
|
break;
|
|
// This stage recolors marked nodes.
|
|
case 3:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
}
|
|
Br.setColor(Node.Black);
|
|
Pr.setColor(Node.Red);
|
|
|
|
stage = 4;
|
|
break;
|
|
// This stage performs rotation operation
|
|
case 4:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Left_Rotate(Pr);
|
|
Br = Pr.getNode(Node.Right_son);
|
|
} else {
|
|
Right_Rotate(Pr);
|
|
Br = Pr.getNode(Node.Left_son);
|
|
}
|
|
if ((Br.getNode(Node.Right_son).getColor() == Node.Black)
|
|
&& (Br.getNode(Node.Left_son).getColor() == Node.Black)) {
|
|
stage = 5;
|
|
} else {
|
|
stage = 7;
|
|
}
|
|
|
|
break;
|
|
// This stage marks nodes that will be recolor.
|
|
case 5:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
}
|
|
stage = 6;
|
|
break;
|
|
// This stage recolors marked nodes.
|
|
case 6:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
}
|
|
Br.setColor(Node.Red);
|
|
node = Pr;
|
|
|
|
if ((node != root) && (node.getColor() == Node.Black)) {
|
|
stage = 2;
|
|
} else if (node.getColor() == Node.Red) {
|
|
stage = 13;
|
|
} else
|
|
stage = 0;
|
|
break;
|
|
// This stage marks nodes that will be recolor or perform other stage.
|
|
case 7:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
if ((Br.getNode(Node.Right_son)).getColor() == Node.Black) {
|
|
stage = 8;
|
|
} else {
|
|
stage = 10;
|
|
DeleteStep();
|
|
}
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
if ((Br.getNode(Node.Left_son)).getColor() == Node.Black) {
|
|
stage = 8;
|
|
} else {
|
|
stage = 10;
|
|
DeleteStep();
|
|
}
|
|
}
|
|
break;
|
|
// This stage recolors marked nodes.
|
|
case 8:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
Br.getNode(Node.Left_son).setColor(Node.Black);
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
Br.getNode(Node.Right_son).setColor(Node.Black);
|
|
}
|
|
Br.setColor(Node.Red);
|
|
stage = 9;
|
|
break;
|
|
// This stage performs rotation operation
|
|
case 9:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
Right_Rotate(Br);
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
Left_Rotate(Br);
|
|
}
|
|
|
|
stage = 10;
|
|
break;
|
|
// This stage marks node that will be recolor.
|
|
case 10:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
}
|
|
|
|
stage = 11;
|
|
break;
|
|
// This stage recolors marked nodes.
|
|
case 11:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Br = Pr.getNode(Node.Right_son);
|
|
Br.getNode(Node.Right_son).setColor(Node.Black);
|
|
} else {
|
|
Br = Pr.getNode(Node.Left_son);
|
|
Br.getNode(Node.Left_son).setColor(Node.Black);
|
|
|
|
}
|
|
if (Br.getColor() != Pr.getColor()) {
|
|
Br.setColor(Pr.getColor());
|
|
}
|
|
if (Pr.getColor() != Node.Black) {
|
|
Pr.setColor(Node.Black);
|
|
}
|
|
|
|
stage = 12;
|
|
break;
|
|
// This stage performs rotation operation.
|
|
case 12:
|
|
Pr = node.getNode(Node.Parent);
|
|
if (node == Pr.getNode(Node.Left_son)) {
|
|
Left_Rotate(Pr);
|
|
} else {
|
|
Right_Rotate(Pr);
|
|
}
|
|
node = root;
|
|
if (node.getColor() == Node.Red) {
|
|
stage = 13;
|
|
} else {
|
|
stage = 0;
|
|
}
|
|
break;
|
|
// This stage marks a node that will be recolored
|
|
case 13:
|
|
stage = 14;
|
|
break;
|
|
// This stage recolors marked node.
|
|
case 14:
|
|
node.setColor(Node.Black);
|
|
stage = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// This method inserts the node 'node' to the tree.
|
|
// it called from the first stage in the InsertStep method.
|
|
// we 'dive' from the root to a leaf according to the node key
|
|
// and insert the node in the proper place.
|
|
private void Tree_Insert() {
|
|
Node n1, n2;
|
|
n1 = root;
|
|
n2 = treeNull;
|
|
while (n1 != treeNull) {
|
|
n2 = n1;
|
|
if (node.getKey() < n1.getKey()) {
|
|
n1 = n1.getNode(Node.Left_son);
|
|
} else {
|
|
n1 = n1.getNode(Node.Right_son);
|
|
}
|
|
}
|
|
node.setNode(Node.Parent, n2);
|
|
if (n2 == treeNull) {
|
|
root = node;
|
|
}
|
|
else {
|
|
if (node.getKey() < n2.getKey()) {
|
|
n2.setNode(Node.Left_son, node);
|
|
} else {
|
|
n2.setNode(Node.Right_son, node);
|
|
}
|
|
}
|
|
// updating the insertion stage.
|
|
if ((node == root) ||
|
|
(node.getNode(Node.Parent).getColor() == Node.Black)) {
|
|
if (root.getColor() == Node.Red) {
|
|
stage = 9;
|
|
} else {
|
|
stage = 0;
|
|
}
|
|
} else {
|
|
stage = 2;
|
|
InsertStep();
|
|
}
|
|
num_of_nodes++; // increasing the number of nodes
|
|
}
|
|
|
|
// This method deletes the node 'node' from the tree.
|
|
// it called from the first stage in the DeleteStep method.
|
|
// if node has at most one son we just remove it and connect
|
|
// his son and parent. If it has 2 sons we delete his successor
|
|
// that has at most one son and replace him with the successor.
|
|
private void Tree_Delete() {
|
|
Node n1, n2, n3;
|
|
if ((node.getNode(Node.Left_son) == treeNull) ||
|
|
(node.getNode(Node.Right_son) == treeNull)) {
|
|
n1 = node;
|
|
} else {
|
|
n1 = Tree_Successor(node);
|
|
}
|
|
|
|
if (n1.getNode(Node.Left_son) != treeNull) {
|
|
n2 = n1.getNode(Node.Left_son);
|
|
} else {
|
|
n2 = n1.getNode(Node.Right_son);
|
|
}
|
|
|
|
n3 = n1.getNode(Node.Parent);
|
|
n2.setNode(Node.Parent, n3);
|
|
if (n3 == treeNull) {
|
|
root = n2;
|
|
} else if (n1 == n3.getNode(Node.Left_son)) {
|
|
n3.setNode(Node.Left_son, n2);
|
|
} else {
|
|
n3.setNode(Node.Right_son, n2);
|
|
}
|
|
|
|
if (n1 != node) {
|
|
node.setKey(n1.getKey());
|
|
}
|
|
|
|
node = n2;
|
|
if (n1.getColor() == Node.Black) {
|
|
if ((node != root) && (node.getColor() == Node.Black)) {
|
|
stage = 2;
|
|
} else if (node.getColor() == Node.Red) {
|
|
stage = 13;
|
|
} else {
|
|
stage = 0;
|
|
}
|
|
} else {
|
|
stage = 0;
|
|
}
|
|
// decrease the number of nodes.
|
|
num_of_nodes--;
|
|
}
|
|
|
|
// This method returns the successor of the node n in the tree.
|
|
private Node Tree_Successor(Node n) {
|
|
Node n1;
|
|
if (n.getNode(Node.Right_son) != treeNull) {
|
|
n = n.getNode(Node.Right_son);
|
|
while (n.getNode(Node.Left_son) != treeNull) {
|
|
n = n.getNode(Node.Left_son);
|
|
}
|
|
return n;
|
|
}
|
|
n1 = n.getNode(Node.Parent);
|
|
while ((n1 != treeNull) && (n == n1.getNode(Node.Right_son))) {
|
|
n = n1;
|
|
n1 = n1.getNode(Node.Parent);
|
|
}
|
|
return n1;
|
|
}
|
|
|
|
// This method performs Left Rotation with n1.
|
|
private void Left_Rotate(Node n1) {
|
|
Node n2;
|
|
|
|
n2 = n1.getNode(Node.Right_son);
|
|
n1.setNode(Node.Right_son, n2.getNode(Node.Left_son));
|
|
if (n2.getNode(Node.Left_son) != treeNull) {
|
|
n2.getNode(Node.Left_son).setNode(Node.Parent, n1);
|
|
}
|
|
n2.setNode(Node.Parent, n1.getNode(Node.Parent));
|
|
if (n1.getNode(Node.Parent) == treeNull) {
|
|
root = n2;
|
|
} else if (n1 == n1.getNode(Node.Parent).getNode(Node.Left_son)) {
|
|
n1.getNode(Node.Parent).setNode(Node.Left_son, n2);
|
|
} else {
|
|
n1.getNode(Node.Parent).setNode(Node.Right_son, n2);
|
|
}
|
|
n2.setNode(Node.Left_son, n1);
|
|
n1.setNode(Node.Parent, n2);
|
|
}
|
|
|
|
// This method performs Right Rotation with n1.
|
|
private void Right_Rotate(Node n1) {
|
|
Node n2;
|
|
|
|
n2 = n1.getNode(Node.Left_son);
|
|
n1.setNode(Node.Left_son, n2.getNode(Node.Right_son));
|
|
if (n2.getNode(Node.Right_son) != treeNull) {
|
|
n2.getNode(Node.Right_son).setNode(Node.Parent, n1);
|
|
}
|
|
n2.setNode(Node.Parent, n1.getNode(Node.Parent));
|
|
if (n1.getNode(Node.Parent) == treeNull) {
|
|
root = n2;
|
|
} else if (n1 == (n1.getNode(Node.Parent)).getNode(Node.Left_son)) {
|
|
n1.getNode(Node.Parent).setNode(Node.Left_son, n2);
|
|
} else {
|
|
n1.getNode(Node.Parent).setNode(Node.Right_son, n2);
|
|
}
|
|
n2.setNode(Node.Right_son, n1);
|
|
n1.setNode(Node.Parent, n2);
|
|
}
|
|
|
|
// This method searches the tree for a node with key 'key', and
|
|
// returns the node on success otherwise treeNull.
|
|
public Node Search(int key) {
|
|
Node node;
|
|
node = root;
|
|
while ((node != treeNull) && (key != node.getKey())) {
|
|
if (key < node.getKey()) {
|
|
node = node.getNode(Node.Left_son);
|
|
} else {
|
|
node = node.getNode(Node.Right_son);
|
|
}
|
|
}
|
|
return node;
|
|
}
|
|
|
|
// This method updates the tree height. it uses a recursive method
|
|
// findHeight.
|
|
private void updateHeight() {
|
|
height = 0;
|
|
if (root != treeNull) {
|
|
findHeight(root, 1);
|
|
}
|
|
}
|
|
|
|
// This is a recursive method that find a node height.
|
|
private void findHeight(Node n, int curr) {
|
|
if (height < curr) {
|
|
height = curr;
|
|
}
|
|
if (n.getNode(Node.Left_son) != treeNull) {
|
|
findHeight(n.getNode(Node.Left_son), curr + 1);
|
|
}
|
|
if (n.getNode(Node.Right_son) != treeNull) {
|
|
findHeight(n.getNode(Node.Right_son), curr + 1);
|
|
}
|
|
}
|
|
|
|
}
|