From 35c284e9a71d45ee76fda93925f76484237d1ae2 Mon Sep 17 00:00:00 2001 From: Ahmed Khaled Date: Fri, 19 Jul 2019 23:14:05 +0200 Subject: [PATCH] feat: added java implementation for red-black trees (#36026) --- .../algorithms/red-black-trees/index.md | 335 ++++++++++++++++++ 1 file changed, 335 insertions(+) diff --git a/guide/english/algorithms/red-black-trees/index.md b/guide/english/algorithms/red-black-trees/index.md index 0b2b54c082..66604dde73 100644 --- a/guide/english/algorithms/red-black-trees/index.md +++ b/guide/english/algorithms/red-black-trees/index.md @@ -35,5 +35,340 @@ Specifically, in a left-leaning red-black 2-3 tree built from N random keys: ->A random successful search examines log2 N − 0.5 nodes. ->The average tree height is about 2 log2 N +### Java Implementation + +##### Class Node.java: + +```java +public class Node { + + private int data, color; //0 - red, 1 - black + private Node left, right, parent; + + public Node(int data) { + this.data = data; + left = right = parent = null; + color = 0; + } + + public int getData() { + return data; + } + + public void setData(int data) { + this.data = data; + } + + public Node getLeft() { + return left; + } + + public void setLeft(Node left) { + this.left = left; + } + + public Node getRight() { + return right; + } + + public void setRight(Node right) { + this.right = right; + } + + public Node getParent() { + return parent; + } + + public void setParent(Node parent) { + this.parent = parent; + } + + public int getColor() { + return color; + } + + public void setColor(int color) { + this.color = color; + } +} +``` + +##### Class RedBlackTree.java: + +```java +package akopensource.rbtrees; + +public class RedBlackTree { + private Node root; + private Node nil = new Node(-404); + + public RedBlackTree(Node root) { + this.root = root; + } + + public RedBlackTree(int data) { + nil.setColor(1); + root = new Node(data); + root.setParent(nil); + root.setRight(nil); + root.setLeft(nil); + root.setColor(1); + } + + public RedBlackTree(){ + nil.setColor(1); + this.root = nil; + } + + public Node search(int data){ + return search(data, this.root); + } + + private Node search(int data, Node node){ + if (node == nil || node.getData() == data) + return node; + if (data < node.getData()) + return search(data, node.getLeft()); + return search(data, node.getRight()); + } + + public void insert(int data){ + Node z = new Node(data); + z.setLeft(nil); + z.setRight(nil); + z.setParent(nil); + + Node node = this.root, n = nil; + while (node != nil){ + n = node; // get leaf node + if(z.getData() < node.getData()) + node = node.getLeft(); + else + node = node.getRight(); + } + z.setParent(n); + if(n==nil) + this.root = z; + else if(z.getData() < n.getData()) + n.setLeft(z); + else + n.setRight(z); + + insertFixup(z); + } + + private void insertFixup(Node z) { + while (z.getParent().getColor() == 0){ + if(z.getParent() == z.getParent().getParent().getLeft()){ + Node uncle = z.getParent().getParent().getRight(); + if (uncle.getColor() == 0){ // case 1 + uncle.setColor(1); + z.getParent().setColor(1); + z.getParent().getParent().setColor(0); + z = z.getParent().getParent(); + } else { + if (z == z.getParent().getRight()) { + z = z.getParent(); + rotateLeft(z); + } + z.getParent().setColor(1); + z.getParent().getParent().setColor(0); + rotateRight(z.getParent().getParent()); + } + } + else{ + Node uncle = z.getParent().getParent().getLeft(); + if(uncle.getColor() == 0){ + uncle.setColor(1); + z.getParent().setColor(1); + z.getParent().getParent().setColor(0); + z = z.getParent().getParent(); + } else { + if (z == z.getParent().getLeft()) { + z = z.getParent(); + rotateRight(z); + } + z.getParent().setColor(1); + z.getParent().getParent().setColor(0); + rotateLeft(z.getParent().getParent()); + } + } + } + root.setColor(1); + } + + private void rotateLeft(Node x){ + Node y = x.getRight(); + + x.setRight(y.getLeft()); + y.getLeft().setParent(x); + + y.setParent(x.getParent()); + if(x == root) + root = y; + else if (x == x.getParent().getLeft()) + x.getParent().setLeft(y); + else x.getParent().setRight(y); + + y.setLeft(x); + x.setParent(y); + } + + private void rotateRight(Node x){ + Node y = x.getLeft(); + + x.setLeft(y.getRight()); + y.getRight().setParent(x); + + y.setParent(x.getParent()); + if(x == root) + root = y; + else if(x == x.getParent().getLeft()) + x.getParent().setLeft(y); + else x.getParent().setRight(y); + + y.setRight(x); + x.setParent(y); + } + + + private void transplant(Node u, Node v){ + if (u.getParent() == nil) + this.root = v; + else if (u == u.getParent().getLeft()) + u.getParent().setLeft(v); + else u.getParent().setRight(v); + v.setParent(u.getParent()); + } + + public void delete(int data){ + Node target = search(data); + Node y = target, x; + int yOriginalColor = y.getColor(); + if (target.getLeft() == nil){ + x = target.getRight(); + transplant(target, target.getRight()); + } else if (target.getRight() == nil){ + x = target.getLeft(); + transplant(target, target.getLeft()); + } else { + y = findMinimum(target.getRight()); + yOriginalColor = y.getColor(); + x = y.getRight(); + + if (y.getParent() == target) { + x.setParent(y); + } + else { + transplant(y, y.getRight()); + y.setRight(target.getRight()); + y.getRight().setParent(y); + } + transplant(target,y); + y.setLeft(target.getLeft()); + y.getLeft().setParent(y); + y.setColor(target.getColor()); + } + if (yOriginalColor == 1) { + deleteFixup(x); + } + } + + private void deleteFixup(Node x) { + Node sibling; + while (x != this.root && x.getColor() == 1){ + if (x == x.getParent().getLeft()){ + sibling = x.getParent().getRight(); + if (sibling.getColor() == 0){ + sibling.setColor(1); + x.getParent().setColor(0); + rotateLeft(x.getParent()); + sibling = x.getParent().getRight(); + } + if (sibling.getLeft().getColor() == 1 && sibling.getRight().getColor() == 1) { + sibling.setColor(0); + x = x.getParent(); + } else { + if (sibling.getRight().getColor() == 1) { + sibling.getLeft().setColor(1); + sibling.setColor(0); + rotateRight(sibling); + sibling = x.getParent().getRight(); + } + sibling.setColor(x.getParent().getColor()); + x.getParent().setColor(1); + sibling.getRight().setColor(1); + rotateLeft(x.getParent()); + x = this.root; + } + } else { + sibling = x.getParent().getLeft(); + if (sibling.getColor() == 0){ + sibling.setColor(1); + x.getParent().setColor(0); + rotateRight(x.getParent()); + sibling = x.getParent().getLeft(); + } + if (sibling.getLeft().getColor() == 1 && sibling.getRight().getColor() == 1){ + sibling.setColor(0); + x = x.getParent(); + } else { + if (sibling.getLeft().getColor() == 1) { + sibling.getRight().setColor(1); + sibling.setColor(0); + rotateLeft(sibling); + sibling = x.getParent().getLeft(); + } + sibling.setColor(x.getParent().getColor()); + x.getParent().setColor(1); + sibling.getLeft().setColor(1); + rotateRight(x.getParent()); + x = this.root; + } + } + } + x.setColor(1); + } + + public Node findMinimum(){ + return findMinimum(this.root); + } + + private Node findMinimum(Node rootNode){ + while (rootNode.getLeft() != nil) + rootNode = rootNode.getLeft(); + return rootNode; + } + + private Node getSuccessor(Node x){ + if (x.getRight() != nil) + return findMinimum(x.getRight()); + Node parent = x.getParent(); + while (parent != nil && x == parent.getRight()){ + x = parent; + parent = parent.getParent(); + } + return parent; + } + + public Node getRoot() { + return root; + } + + public void setRoot(Node root) { + this.root = root; + } + public void traverseInorder (Node rootNode){ + if(rootNode != nil){ + traverseInorder(rootNode.getLeft()); + System.out.println(rootNode.getData() + " color " + rootNode.getColor()); + traverseInorder(rootNode.getRight()); + } + } +} +``` + +- Note: most of this code is brought from "Introduction to Algorithms" book written by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein. + #### More Information: * [Video from Algorithms and Data Structures](https://www.youtube.com/watch?v=2Ae0D6EXBV4)