blob: b67a881d43dbb0903af64577694d3c494caf8752 [file] [log] [blame]
/*
* Copyright (c) 2008, 2018, 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;
import nsk.share.TestFailure;
//import Node;
// 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 heigth ,it is updated
// in each operation.
// since the algorithem 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 initialize the object fields.
public RBTree()
{
root = treeNull;
node = treeNull;
num_of_nodes = 0;
height = 0;
action = NOP;
stage = 0;
}
// This method return the root of the tree.
public Node getRoot()
{
return root;
}
// This method return the number of nodes in the tree.
public int getNodes()
{
return num_of_nodes;
}
// This method return the heigth of the tree.
public int getHeight()
{
return height;
}
// This method inserts k into the Red Black Tree
public boolean RBInsert(int k)
{
Thread Pause = new Thread(); // this thread is used for delay
// between the stages.
if (action != NOP) // checking similar to the RB_Insert method
{
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;
}
if (Search(k) == treeNull) // Check if there is already node with key k.
{
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;
while (stage != 0) // This is the loop that perform all the
{ // operation steps.
InsertStep(); // perform one step
updateHeight(); // update the tree height
}
action = NOP; // set the action to NoOPretion.
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)
{
Thread Pause = new Thread(); // this thread is used for delay
// between the stages.
if (action != NOP)
{ // checking like in RB_Delete method
System.out.println
("Only one operation can be done at a time.");
return false;
}
node = Search(k);
if (node != treeNull) // Check if there is a node with key k.
{
action = DELETE;
stage = 1;
while (stage != 0) // this loop perform all the operation
{ // steps.
DeleteStep(); // perform one step
updateHeight(); // update the tree height
}
action = NOP;
return true;
}
else
System.out.println
("Deletion failed. This key doesn't exist.");
return false;
}
// This method perform one step in the insertion operation.
// If perform a step acording 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()
{
Node Pr,GrPr,Un; // Pr is parent, GrPr is grandparent
// and Un is uncle.
switch (stage)
{
case 1: // Inserting a node to the tree
/*
System.out.println // send a message to the screen
(new String("Inserting ")
.concat(Integer.toString(node.getKey())));
*/
Tree_Insert(); // inserting an element to the tree
break;
case 2: // mid stage that move to algorithem to the
// proper next stage, and send proper message
// to the screen
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;
case 3: // This stage marks node that will be recolored
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;
case 4: // this stage recolor marked nodes.
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;
case 5: // This stage perform rotation operation
Pr = node.getNode(Node.Parent);
if (node == Pr.getNode(Node.Left_son))
Left_Rotate(node);
else
Right_Rotate(node);
stage = 6;
break;
case 6: // This stage marks nodes that will be recolor.
Pr = node.getNode(Node.Parent);
GrPr = Pr.getNode(Node.Parent);
stage = 7;
break;
case 7: // This stage recolor marked nodes.
Pr = node.getNode(Node.Parent);
Pr.setColor(Node.Black);
GrPr = Pr.getNode(Node.Parent);
GrPr.setColor(Node.Red);
stage = 8;
break;
case 8: // This stage perform rotation operation
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;
case 9: // this stage mark the root.
stage = 10;
break;
case 10: // This stage recolor the root.
root.setColor(Node.Black);
stage = 0;
break;
}
}
// This method perform one step in the deletion operation.
// If perform a step acording 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()
{
Node Pr,Br; // Pr is Parent ,Br is Brother
switch (stage)
{
case 1: // This stage delete a node from the tree.
/*
System.out.println
(new String("Deleting ")
.concat(Integer.toString(node.getKey())));
*/
Tree_Delete();
break;
case 2: // This stage marks a nodes that will be recolored
// or perform other stage.
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;
case 3: // this stage recolor marked nodes.
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;
case 4: // this stage perform rotation operation
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;
case 5: // this stage marks nodes that will be recolor.
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;
case 6: // This stage recolor marked nodes.
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;
case 7: // this stage marks nodes that will be recolor
// or perform other stage.
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;
case 8: // this stage recolor marked nodes.
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;
case 9: // this stage perform rotation operation
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;
case 10: // This stage marks node that will be recolor.
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;
case 11: // this stage recolor marked nodes.
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;
case 12: // this stage perform rotation operation.
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;
case 13: // this stage marks a node that will be recolor
stage = 14;
break;
case 14: // this stage recolor marked node.
node.setColor(Node.Black);
stage = 0;
break;
}
}
// This method insert the node 'node' to the tree.
// it called from the first stage in the InsertStep method.
// we 'dive' from the root to a leaf acording 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);
}
//Parent.display.drawTree();
// 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 delete 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;
num_of_nodes--; // decrease the number of nodes.
}
// This method return 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 perform 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 perform 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 search the tree for a node with key 'key', and
// return 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 update 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);
}
}