jdk-24/test/hotspot/jtreg/vmTestbase/jit/graph/RBTree.java
Igor Ignatyev c3b33c0631 8225654: rework vmTestbase/jit/graph
Reviewed-by: thartmann, neliasso
2019-10-11 09:43:41 -07:00

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);
}
}
}