feat: added java implementation for red-black trees (#36026)

This commit is contained in:
Ahmed Khaled
2019-07-19 23:14:05 +02:00
committed by Quincy Larson
parent 830def0604
commit 35c284e9a7

View File

@ -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)