package com.interview.basics.model.tree;
/**
* Created with IntelliJ IDEA.
* User: stefanie
* Date: 10/20/14
* Time: 4:19 PM
*/
public class RedBlackTree<T extends Comparable<T>> extends BinarySearchTree<T> {
static class RedBlackTreeNode<T extends Comparable<T>> extends BinaryTreeNode<T> {
public static final boolean BLACK = false;
public static final boolean RED = true;
public boolean color = RED;
public RedBlackTreeNode(T value) {
super(value);
}
public boolean isRed(BinaryTreeNode node) {
return ((node != null) && node instanceof RedBlackTreeNode
&& ((RedBlackTreeNode) node).color == RED);
}
public RedBlackTreeNode rotateRight() {
RedBlackTreeNode tmp = (RedBlackTreeNode) this.left;
this.setLeft(tmp.right);
tmp.setRight(this);
tmp.color = this.color;
this.color = RED;
return tmp;
}
public RedBlackTreeNode rotateLeft() {
RedBlackTreeNode tmp = (RedBlackTreeNode) this.right;
this.setRight(tmp.left);
tmp.setLeft(this);
tmp.color = this.color;
this.color = RED;
return tmp;
}
public void flipColors() {
this.color = RED;
((RedBlackTreeNode) this.left).color = BLACK;
((RedBlackTreeNode) this.right).color = BLACK;
}
}
public RedBlackTree(T[] values) {
super(values);
}
public RedBlackTree(BinaryTreeNode root) {
super(root);
}
public RedBlackTree(){
}
private RedBlackTreeNode fixUp(RedBlackTreeNode node) {
if (node.isRed(node.right) && !node.isRed(node.left)) node = node.rotateLeft();
if (node.isRed(node.left) && node.isRed(node.left.left)) node = node.rotateRight();
if (node.isRed(node.left) && node.isRed(node.right)) node.flipColors();
return node;
}
@Override
protected BinaryTreeNode<T> insert(BinaryTreeNode<T> node, T element) {
if (node == null) return new RedBlackTreeNode<>(element);
int cmp = node.value.compareTo(element);
if (cmp == 0) node.count++;
else if (cmp > 0) node.setLeft(insert(node.left, element));
else node.setRight(insert(node.right, element));
return fixUp((RedBlackTreeNode) node);
}
private RedBlackTreeNode<T> moveRedRight(RedBlackTreeNode<T> node) {
if (node.isRed(node.left) && node.isRed(node.right)) node.flipColors();
if (node.left != null && node.isRed(node.left.left)) {
node = node.rotateRight();
if (node.isRed(node.left) && node.isRed(node.right)) node.flipColors();
}
return node;
}
@Override
public void deleteMax() {
root = deleteMax((RedBlackTreeNode) root);
((RedBlackTreeNode) root).color = RedBlackTreeNode.BLACK;
}
protected RedBlackTreeNode deleteMax(RedBlackTreeNode<T> node) {
if(node == null) return null;
if (node.isRed(node.left)) node = node.rotateRight();
if (node.right == null) return (RedBlackTreeNode)node.left;
if (!node.isRed(node.right) && !node.isRed(node.right.left))
node = moveRedRight(node);
node.left = deleteMax((RedBlackTreeNode)node.left);
return fixUp(node);
}
private RedBlackTreeNode moveRedLeft(RedBlackTreeNode node){
if (node.isRed(node.left) && node.isRed(node.right)) node.flipColors();
if (node.right != null && node.isRed(node.right.left)){
node.right = ((RedBlackTreeNode)node.right).rotateRight();
node = node.rotateLeft();
if (node.isRed(node.left) && node.isRed(node.right)) node.flipColors();
}
return node;
}
@Override
public void deleteMin() {
root = deleteMin((RedBlackTreeNode) root);
((RedBlackTreeNode) root).color = RedBlackTreeNode.BLACK;
}
protected RedBlackTreeNode<T> deleteMin(RedBlackTreeNode<T> node) {
if (node.left == null) return (RedBlackTreeNode)node.right;
if (!node.isRed(node.left) && node.left != null && !node.isRed(node.left.left))
node = moveRedLeft(node);
node.left = deleteMin((RedBlackTreeNode)node.left);
return fixUp(node);
}
@Override
protected BinaryTreeNode<T> delete(BinaryTreeNode<T> node, T element) {
if(node == null) return null;
int cmp = node.value.compareTo(element);
RedBlackTreeNode h = (RedBlackTreeNode)node;
if (cmp > 0){
if (!h.isRed(h.left) && !h.isRed(h.left.left))
h = moveRedLeft(h);
h.left = delete(h.left, element);
} else {
if (h.isRed(h.left)) h = moveRedRight(h);
if (cmp == 0 && (h.right == null)) return null;
if (!h.isRed(h.right) && !h.isRed(h.right.left))
h = moveRedRight(h);
if (cmp == 0){
h.value = min(h.right);
h.right = deleteMin((RedBlackTreeNode)h.right);
} else h.right = delete(h.right, element);
}
return fixUp(h);
}
}