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