// Function to add node to the tree.The add function is from psuedocode on page 315 of CRLS //input: this is calling object, the RedBlack tree itself. z is a new Redblack Tree node to be inserted into this //output: Z node is added to the tree, size is added and the new height of the tree calculated public void add(RedBlackNode z) { RedBlackNode y = new RedBlackNode(); y = this.nil; RedBlackNode x = new RedBlackNode(); x = this.root; //go until you hit a leaf node and insert at bottom of tree if you do while (x != this.nil) { //keeping track of previvous parent y = x; //going down the left or right sub tree if (z.Data < x.Data) { x = x.Left; } else { x = x.Right; } } //after exiting the while loop we have figured out where to place //node z and y is his parent. z.Parent = y; //if y was nil, then z is the root. if (y == this.nil) { this.root = z; }//less than y than it goes left of y else if(z.Data < y.Data) { y.Left = z; } else { y.Right = z; } //Setting everthing for z z.Left = this.nil; z.Right = this.nil; z.Color = RedBlackNode.RED; treeSize = treeSize + 1; //fixing the redblack colors of the nodes in the tree //Console.WriteLine("Inserted " + z.Data); this.InsertFixup(z); }
// defualt constructor for a Redblack tree public RedBlack() { treeSize = 0; height = 0; nil = new RedBlackNode(); nil.Left = null; nil.Right = null; nil.Data = -1; nil.Parent = null; nil.Size = 0; nil.Color = RedBlackNode.BLACK; root = nil; }
static void Main(string[] args) { Console.Write("What is full path to the data file?"); string data = Console.ReadLine(); Console.WriteLine("Expecting the file to be tab delimited, so key\toperation for each line"); Console.Write("What is full path to the DynamicOps file?"); string dofile = Console.ReadLine(); RedBlack tree = new RedBlack(); //tree to hold all the nodes string date = DateTime.Now.Ticks.ToString(); string reportName = "report" + date + ".txt"; Console.WriteLine("name of the report file: " + reportName ); TextWriter report = new StreamWriter(reportName); //file to write out the report int counter = 0; //count the lines in the file string line; // line in the file // Read the file and add the node line by line. try { System.IO.StreamReader file = new System.IO.StreamReader(data); while ((line = file.ReadLine()) != null) { RedBlackNode x = new RedBlackNode(); x.Data = Convert.ToInt32(line); // line comes in as a string, converting to a int to add to the node tree.add(x); //adding the node to the tree if (counter % 1000 == 0) { Console.WriteLine("Adding node " + counter); } // letting you know something is going on...it takes a long time to add nodes and calculate their size of the subtree if (counter == 100) { Console.WriteLine("The height of the tree is after 100 inserts " + tree.Height()); report.WriteLine("The height of the tree is after 100 inserts " + tree.Height()); } if (counter == 1000) { Console.WriteLine("The height of the tree is after 1000 inserts " + tree.Height()); report.WriteLine("The height of the tree is after 1000 inserts " + tree.Height()); } counter++; } file.Close(); //closing the file like a good programmer ///* // * All the operations as asked from the original data set // * Find the 10 integers in the original data set with the following percentiles: 45 86 85 39 63 76 68 95 5 96. // * Also find the rankings in percentile of the following 10 integers using the original data set: // * 12858 46144 17350 17043 35198 62194 5913 18535 57524 23484. // * */ Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Tree size " + tree.returnTreeSize()); //normal tree size, just adding the nodes as insert Console.WriteLine("Calculated Tree size " + tree.size()); //tracks the nodes size of the subtree Console.WriteLine("Tree min value " + tree.minimum().Data); //the minimum node in the tree Console.WriteLine("Tree max value " + tree.maximum().Data); //the max node in the tree Console.WriteLine("tree height " + tree.Height()); // the height of the tree with the original data set Console.WriteLine("tree root : " + tree.returnRoot().Data); //the root of the tree report.WriteLine("Tree size " + tree.returnTreeSize()); //normal tree size, just adding the nodes as insert report.WriteLine("Calculated Tree size " + tree.size()); //tracks the nodes size of the subtree report.WriteLine("Tree min value " + tree.minimum().Data); //the minimum node in the tree report.WriteLine("Tree max value " + tree.maximum().Data); //the max node in the tree report.WriteLine("tree height " + tree.Height()); // the height of the tree with the original data set report.WriteLine("tree root : " + tree.returnRoot().Data); //the root of the tree //uncommit this if you want the tree to be printed out in preorder traversal // tree.PreOrder(); Console.WriteLine(); Console.WriteLine(); //getting the nodes at the percentiles asked for Console.WriteLine("45 percentile: " + tree.orderSelect(45).Data); Console.WriteLine("86 percentile: " + tree.orderSelect(86).Data); Console.WriteLine("85 percentile: " + tree.orderSelect(85).Data); Console.WriteLine("39 percentile: " + tree.orderSelect(39).Data); Console.WriteLine("63 percentile: " + tree.orderSelect(63).Data); Console.WriteLine("76 percentile: " + tree.orderSelect(76).Data); Console.WriteLine("68 percentile: " + tree.orderSelect(68).Data); Console.WriteLine("95 percentile: " + tree.orderSelect(95).Data); Console.WriteLine("5 percentile: " + tree.orderSelect(5).Data); Console.WriteLine("96 percentile: " + tree.orderSelect(50).Data); report.WriteLine("45 percentile: " + tree.orderSelect(45).Data); report.WriteLine("86 percentile: " + tree.orderSelect(86).Data); report.WriteLine("85 percentile: " + tree.orderSelect(85).Data); report.WriteLine("39 percentile: " + tree.orderSelect(39).Data); report.WriteLine("63 percentile: " + tree.orderSelect(63).Data); report.WriteLine("76 percentile: " + tree.orderSelect(76).Data); report.WriteLine("68 percentile: " + tree.orderSelect(68).Data); report.WriteLine("95 percentile: " + tree.orderSelect(95).Data); report.WriteLine("5 percentile: " + tree.orderSelect(5).Data); report.WriteLine("96 percentile: " + tree.orderSelect(50).Data); //in order to find the rank of the node we have to find the node first and then do the calculation //if a -1 is return the node was not find in the tree.... Console.WriteLine(); Console.WriteLine(); report.WriteLine(); report.WriteLine(); RedBlackNode search = new RedBlackNode(); search = tree.search(12858); Console.WriteLine("12858 rank is: " + tree.osRank(search)); report.WriteLine("12858 rank is: " + tree.osRank(search)); search = tree.search(46144); Console.WriteLine("46144 rank is: " + tree.osRank(search)); report.WriteLine("46144 rank is: " + tree.osRank(search)); search = tree.search(17350); Console.WriteLine("17350 rank is: " + tree.osRank(search)); report.WriteLine("17350 rank is: " + tree.osRank(search)); search = tree.search(17043); Console.WriteLine("17043 rank is: " + tree.osRank(search)); report.WriteLine("17043 rank is: " + tree.osRank(search)); search = tree.search(35198); Console.WriteLine("35198 rank is: " + tree.osRank(search)); report.WriteLine("35198 rank is: " + tree.osRank(search)); search = tree.search(62194); Console.WriteLine("62194 rank is: " + tree.osRank(search)); report.WriteLine("62194 rank is: " + tree.osRank(search)); search = tree.search(5913); Console.WriteLine("5913 rank is: " + tree.osRank(search)); report.WriteLine("5913 rank is: " + tree.osRank(search)); search = tree.search(18535); Console.WriteLine("18535 rank is: " + tree.osRank(search)); report.WriteLine("18535 rank is: " + tree.osRank(search)); search = tree.search(57524); Console.WriteLine("57524 rank is: " + tree.osRank(search)); report.WriteLine("57524 rank is: " + tree.osRank(search)); search = tree.search(23484); Console.WriteLine("23484 rank is: " + tree.osRank(search)); report.WriteLine("23484 rank is: " + tree.osRank(search)); //variables to add or delete the node in the DynamicOps file char[] delimiters = { '\t' }; // Program expects the data in key\toperation where key is the data of the node to be operated on, and operations is a 1 (add) or 0 (delete), string[] words; // string array that will contain the the key at words[0] and the operation at words[1] int key = -1; int operation = -1; Console.WriteLine(); Console.WriteLine(); counter = 0; System.IO.StreamReader DynamicOps = new System.IO.StreamReader(dofile); while ((line = DynamicOps.ReadLine()) != null) { RedBlackNode node = new RedBlackNode(); words = line.Split(delimiters); key = Convert.ToInt32(words[0]); operation = Convert.ToInt32(words[1]); node.Data = key; if (operation == 0) //delete the key if operation is a 0 { Console.WriteLine("Deleting node " + node.Data); report.WriteLine("Deleting node " + node.Data); node = tree.search(key); if (node.Data == -1) { Console.WriteLine("Node was not found in the tree"); report.WriteLine("Node was not found in the tree"); } else { tree.delete(node); Console.WriteLine("The height of the tree is " + tree.Height()); report.WriteLine("The height of the tree is " + tree.Height()); } } else //add the key if the operation is a 1 { Console.WriteLine("Adding node " + node.Data); report.WriteLine("Adding node " + node.Data); tree.add(node); Console.WriteLine("The height of the tree is " + tree.Height()); report.WriteLine("The height of the tree is " + tree.Height()); } counter++; } Console.WriteLine(); Console.WriteLine(); Console.WriteLine("Tree size " + tree.returnTreeSize()); //normal tree size, just adding the nodes as insert Console.WriteLine("Calculated Tree size " + tree.size()); //tracks the nodes size of the subtree Console.WriteLine("Tree min value " + tree.minimum().Data); //the minimum node in the tree Console.WriteLine("Tree max value " + tree.maximum().Data); //the max node in the tree Console.WriteLine("tree height " + tree.Height()); // the height of the tree with the original data set Console.WriteLine("tree root : " + tree.returnRoot().Data); //the root of the tree report.WriteLine(); report.WriteLine(); report.WriteLine("Tree size " + tree.returnTreeSize()); //normal tree size, just adding the nodes as insert report.WriteLine("Calculated Tree size " + tree.size()); //tracks the nodes size of the subtree report.WriteLine("Tree min value " + tree.minimum().Data); //the minimum node in the tree report.WriteLine("Tree max value " + tree.maximum().Data); //the max node in the tree report.WriteLine("tree height " + tree.Height()); // the height of the tree with the original data set report.WriteLine("tree root : " + tree.returnRoot().Data); //the root of the tree file.Close(); } catch (Exception e) { Console.WriteLine(e.Message); report.WriteLine(e.Message); } Console.WriteLine("finish"); Console.ReadLine(); report.WriteLine("finish"); //report.ReadLine(); report.Close(); }
//Private member function that recurses the tree //input: a node x, this case the root of the tree //output: the root of the trees farthest left child, the minimum node of the tree private RedBlackNode treeMin(RedBlackNode x) { if (x.Left == this.nil) { return x; } else { x = treeMin(x.Left); } return x; }
//Private member function that recurses the tree //input: node x, the root of the tree //output: the root of the tree's farhtest right hicld, the max node of the tree. private RedBlackNode treeMax(RedBlackNode x) { if (x.Right == nil) { return x; } else { x = treeMax(x.Right); } return x; }
//transplant from CLSR page 323. This function replaces the subtree of one subtree as a child of its parent with another subtree //input: two nodes of the tree //output: repalces the subtree rooted at node u with the subtree rooted at node v, // node u's parent becomes node v's parent and u's parent ends up having v as its appropriate child. private void Transplant(RedBlackNode u, RedBlackNode v) { if (u.Parent == this.nil) { this.root = v; } else if(u == u.Parent.Left) { u.Parent.Left = v; } else { u.Parent.Right = v; } v.Parent = u.Parent; }
//Private member function that corrects the size of the a node after insertions or deletions //input: a node x //output: x and all of x's parent nodes sizes are updated. private int sizeAll(RedBlackNode x) { if (x.Right == nil && x.Left == nil) //at a leaf node { x.Size = x.Right.Size + x.Left.Size + 1; return x.Size; } else if (x.Left == nil) // continue down the right subtree { x.Size = sizeAll(x.Right) + x.Left.Size + 1; return x.Size; } else if (x.Right == nil) // continue down the left subtree { x.Size = sizeAll(x.Left) + x.Right.Size + 1; return x.Size; } else // this node has two children so begin down the left and then down the right { x.Size = sizeAll(x.Left) + sizeAll(x.Right) + 1; return x.Size; } }
//Private member function that recurses the tree to find a node //input: the root of the tree and a node to search for //output: true if the node is in the tree, false otherwise private RedBlackNode searchRec(RedBlackNode x, int search) { if(x == nil)// at a sentenil node did not find it return false { return this.nil; } else if (x.Data == search) //found it! { return x; } else if (search >= x.Data) // what we are looking for is in the right subtree { return searchRec(x.Right, search); } else if (search < x.Data) // what we are looking for is in the left subtree { return searchRec(x.Left, search); } else //not there again so return nil { return this.nil; } }
//rotate right //input: node x, at which to pivot rotate left //output: The right rotation pivots around the link from x to y. // It makes y the new root of the subtree, with x as y's right child and y's right child as x's left private void RightRotate(RedBlackNode x) { RedBlackNode y; y = x.Left; x.Left = y.Right; if (y.Right != this.nil) { y.Right.Parent = x; } y.Parent = x.Parent; if (x.Parent == this.nil) { this.root = y; } else if (x == x.Parent.Right) { x.Parent.Right = y; } else { x.Parent.Left = y; } y.Right = x; x.Parent = y; }
//Private member function PreOrderWork is the recursive worker function the traverses the tree and prints it out //input: a Redblack node, the root of the calling tree //output: A list of the tree in preorder fashion private void PreOrderWork(RedBlackNode x) { if (x == nil) { return; } Console.WriteLine("Parent " + x.Parent.Data + " visiting " + x.Data + " Color " + x.Color + " Size " + x.Size); PreOrderWork(x.Left); PreOrderWork(x.Right); }
//private member function that recursively finds the node at a given rank i //input: a node and the rank to search for //output: the node at given rank i private RedBlackNode orderSelectRec(RedBlackNode x, int i ) { int r = x.Left.Size + 1; if (i == r) { return x; } else if (i <= r) { return orderSelectRec(x.Left, i); } else { return orderSelectRec(x.Right, i - r); } }
// Private member function that Recursively finds the height of the tree //input: a RedBlack node, the root of the tree and and interger to keep track of the height //output: the height of the tree to be returned to the Public Height function private int heightRec(RedBlackNode x, int count) { if (x == this.nil) //if node is sentinel then return { return -1; } else { count = max(heightRec(x.Left, count) , heightRec(x.Right, count)) + 1; } height = count; return count; }
//RB delete fixup //input: node z, where the node z was removed from the tree //output: The RedBlack properites of the tree are corrected as result of the deletion private void deleteFixup(RedBlackNode x) { RedBlackNode w = new RedBlackNode(); while (x != this.root && x.Color == RedBlackNode.BLACK) { if (x == x.Parent.Left) { w = x.Parent.Right; if (w.Color == RedBlackNode.RED) { w.Color = RedBlackNode.BLACK; x.Parent.Color = RedBlackNode.RED; LeftRotate(x.Parent); w = x.Parent.Right; } if (w.Left.Color == RedBlackNode.BLACK && w.Right.Color == RedBlackNode.BLACK) { w.Color = RedBlackNode.RED; x = x.Parent; } else { if (w.Right.Color == RedBlackNode.BLACK) { w.Left.Color = RedBlackNode.BLACK; w.Color = RedBlackNode.RED; x = x.Parent; RightRotate(w); w = x.Parent.Right; } w.Color = x.Parent.Color; x.Parent.Color = RedBlackNode.BLACK; LeftRotate(x.Parent); x = this.root; } } else { w = x.Parent.Left; if (w.Color == RedBlackNode.RED) { w.Color = RedBlackNode.BLACK; x.Parent.Color = RedBlackNode.RED; RightRotate(x.Parent); w = x.Parent.Left; } if (w.Left.Color == RedBlackNode.BLACK && w.Right.Color == RedBlackNode.BLACK) { w.Color = RedBlackNode.RED; x = x.Parent; } else { if (w.Left.Color == RedBlackNode.BLACK) { w.Right.Color = RedBlackNode.BLACK; w.Color = RedBlackNode.RED; x = x.Parent; LeftRotate(w); w = x.Parent.Left; } w.Color = x.Parent.Color; x.Parent.Color = RedBlackNode.BLACK; RightRotate(x.Parent); x = this.root; }//end inner else }//end outter else }//end of while loop }
//public member function that returns the rank of the node sent //input: a node x //output: the rank of the node x in tree public int osRank(RedBlackNode x) { int r = x.Left.Size + 1; RedBlackNode y = x; while (y != this.root) { if (y == y.Parent.Right) { r = r + y.Parent.Left.Size + 1; } y = y.Parent; } return r; }
//RB insert fixup //input: node z, where the node z was inserted into the tree //output: The RedBlack properites of the tree are corrected as a result from the insertion. public void InsertFixup(RedBlackNode z) { RedBlackNode y; while (z.Parent.Color == RedBlackNode.RED) { if (z.Parent == z.Parent.Parent.Left) { y = z.Parent.Parent.Right; if (y != nil && y.Color == RedBlackNode.RED) { z.Parent.Color = RedBlackNode.BLACK; y.Color = RedBlackNode.BLACK; z.Parent.Parent.Color = RedBlackNode.RED; z = z.Parent.Parent; } else { if (z == z.Parent.Right) { z = z.Parent; LeftRotate(z); //left rotate at z } z.Parent.Color = RedBlackNode.BLACK; // make Parent black z.Parent.Parent.Color = RedBlackNode.RED; // make grandparent black RightRotate(z.Parent.Parent); // rotate right } } else { // x's Parent is on the Right subtree // this code is the same as above with "Left" and "Right" swapped y = z.Parent.Parent.Left; if (y != null && y.Color == RedBlackNode.RED) { z.Parent.Color = RedBlackNode.BLACK; y.Color = RedBlackNode.BLACK; z.Parent.Parent.Color = RedBlackNode.RED; z = z.Parent.Parent; } else { if (z == z.Parent.Left) { z = z.Parent; RightRotate(z); } z.Parent.Color = RedBlackNode.BLACK; z.Parent.Parent.Color = RedBlackNode.RED; LeftRotate(z.Parent.Parent); } } } this.root.Color = RedBlackNode.BLACK; //recalculate the size of everyone's subtree sizeAll(root) ; }
//Public member function to remove a node from the calling tree //input: z, the node to be removed from the calling object, the tree //output: Z is removed from the tree and the node's color are fixed. public void delete(RedBlackNode z) { RedBlackNode y = z; RedBlackNode x = new RedBlackNode(); int yOriginalColor = y.Color; if (z.Left == nil) //z only has a right child { x = z.Right; this.Transplant(z, z.Right); //swap z with z's right child } else if (z.Right == nil) //z only has a left child { x = z.Left; this.Transplant(z, z.Left); // swap z with z's left child } else // z has two children { y = treeMin(z.Right); // z's replacement yOriginalColor = y.Color; x = y.Right; if (y.Parent == z) { x.Parent = y; } else { this.Transplant(y, y.Right); y.Right = z.Right; y.Right.Parent = y; } this.Transplant(z, y); y.Left = z.Left; y.Left.Parent = y; y.Color = z.Color; } if (yOriginalColor == RedBlackNode.BLACK) { //Console.WriteLine("I need to call delete fix up"); this.deleteFixup(x); } treeSize = treeSize - 1; root.Size = sizeAll(root); }