How do I write my method for balancing my BST? - java

So I have written an implementation of a BST in Java. My goal is to make it balanced aswell, more precisly an AVL tree. I am having some problem though, I don't know how to implement the trinodeRestructering method(ie the method that balances the tree) I have tried various things but these pointers are sometimes difficult to deal with and I am not sure how to do this recursivly. Down below is my code for adding a new element and the method to check if we are more than 2 steps difference in the tree.
add and balancing method:
private TreeNode insert(TreeNode currN, TreeNode newN) {
if (currN == null) {
return newN;
}
if (currN.getData() == newN.getData()) {
throw new IllegalArgumentException("Value already exists.");
}
if (newN.getData() < currN.getData()) {
if (currN.getLeft() == null) {
currN.setLeft(newN);
} else {
insert(currN.getLeft(), newN);
}
} else {
if (currN.getRight() == null) {
currN.setRight(newN);
} else {
insert(currN.getRight(), newN);
}
}
if (needBalancing()) {
trinodeRestructering(currN);
}
return currN;
}
private TreeNode trinodeRestructering(TreeNode currN) {
//Not sure what to do here.
return currN;
}
height checking method.
public boolean needBalancing(){
if(height(root) == -1){ // true if we need to balance
return true;
}else{
return false;
}
}
private int height(TreeNode node){
if (node == null)
return 0;
int left = height(node.getLeft());
int right = height(node.getRight());
if (left == -1 || right == -1)
return -1;
if (Math.abs(left - right) > 1) {
return -1;
}
return Math.max(left, right) + 1;
}
I might add that I got an working inOrder method, perhaps I could use it to balance my tree?

Related

Fatal Exception: java.lang.IllegalArgumentException: Comparison method violates its general contract

I know there many similar questions and I have received big help by reading answers to those questions, however I am not able to see how is my client facing this problem. And there is only one client who is facing this problem.
I have a List, and I am sorting that list using Comparator interface. Does any of you see problem with the following code?
private static class BiologySamplesComparator implements Comparator<BiologySample>, Serializable {
#Override
public int compare(BiologySample left, BiologySample right) {
if (left == right || (left != null && right != null && left.getSampleDateTime() == right.getSampleDateTime())) {
return 0;
}
if (left == null || left.getSampleDateTime() == null) {
return 1;
}
if (right == null || right.getSampleDateTime() == null) {
return -1;
}
return right.getSampleDateTime().compareTo(left.getSampleDateTime());
}
}
And this how I am calling this function
Collections.sort(biologySamples, new BiologySamplesComparator());
I know that the main problem in this kind of scenario is Transitivity. However I couldn't figure what is violating that rule.
This how getSampleDateTime() is returning date Fri Apr 09 17:00:00 PDT 2021
Update
This is how I was able to fix my problem.
I hope this helps, I was stuck for so long on this problem.
private static class BiologySamplesComparator implements Comparator<BiologySample>, Serializable {
#Override
public int compare(BiologySample left, BiologySample right) {
if (left == null) {
if (right == null) {
return 0;
} else {
return 1;
}
} else if (right == null) {
return -1;
} else if (left == right) {
return 0;
}
if (left.getSampleDateTime() == null) {
if (right.getSampleDateTime() == null) {
return 0;
} else {
return 1;
}
} else if (right.getSampleDateTime() == null) {
return -1;
} else if (left.getSampleDateTime() == right.getSampleDateTime()) {
return 0;
}
return right.getSampleDateTime().compareTo(left.getSampleDateTime());
}
}
You have a possible inconsistency when comparing a null "sample" to a non-null sample with a null timestamp.
Sample a = null;
Sample b = new Sample(null);
bsc.compare(a, b); // -> 1, a > b
bsc.compare(b, a); // -> 1, b > a
First, you should replace the Date in your sample class with Instant if at all possible, and then make your life simpler by saying this:
public static final Comparator<Sample> ORDER_BY_TIMESTAMP =
Comparator.nullsLast(Comparator.comparing(
Sample::getDateTime,
Comparator.nullsLast(Comparator.naturalOrder())
);
If you can rule out null values, even simpler:
Comparator.comparing(Sample::getDateTime);
I was missing some conditional for some cases and this is how I was able to solve my problem.
private static class BiologySamplesComparator implements Comparator<BiologySample>, Serializable {
#Override
public int compare(BiologySample left, BiologySample right) {
if (left == null) {
if (right == null) {
return 0;
} else {
return 1;
}
} else if (right == null) {
return -1;
} else if (left == right) {
return 0;
}
if (left.getSampleDateTime() == null) {
if (right.getSampleDateTime() == null) {
return 0;
} else {
return 1;
}
} else if (right.getSampleDateTime() == null) {
return -1;
} else if (left.getSampleDateTime() == right.getSampleDateTime()) {
return 0;
}
return right.getSampleDateTime().compareTo(left.getSampleDateTime());
}
}
courtesy of Why does my compare methd throw IllegalArgumentException sometimes?

A non-recursive tree node removal method?

How is the best way to go about writing a non-recursive node removal method?
I have this to start things off:
public deezNodes remove(int x) {
if (this == nullnode ) return nullnode;
if (x < this.iData) {
this.left = this.left.remove(x);
} else if (x > this.iData) {
this.right = this.right.remove(x);
} else if (this.left == nullnode) {
return this.right;
} else if (this.right == nullnode ) {
return this.left;
} else { // Two children
this.iData = (this.left).rmLarge(this).iData;
}
return this;
}
My kneejerk response would be replacing instances of recursion with further if/else clauses until the node is found. I'm wondering if there is a more elegant way.
Thanks for the help!

Binary-Search Tree

Here is my code to find position of a certain element. And I am using Binary tree to store my Dictionary I want to know why it shows warning for Comparable-type. I have to use this in my project where element is a string type.
public int get(Comparable element){
return getPosition(element,root);
}
private int getPosition(Comparable element, TreeNode root){
int count = 0;
if (root == null){
return -1;
}else{
Stack t = new Stack();
t.push(root);
while(!t.empty()){
TreeNode n = (TreeNode)t.pop();
if(element.compareTo(n.value)==0){
return count;
}else{
if(n.getLeftTree()!=null){
t.push(n.getLeftTree());
count++;
}
if (n.getRightTree()!= null){
t.push(n.getRightTree());
count++;
}
}
}
return -1;
}
}
The java generic typing parameters are missing <...>.
public int get(Comparable<?> element){
return getPosition(element, root);
}
private int getPosition(Comparable<?> element, TreeNode root) {
int count = 0;
if (root == null) {
return -1;
} else {
Stack<TreeNde> t = new Stack<>();
t.push(root);
while (!t.empty()) {
TreeNode n = t.pop();
if (element.compareTo(n.value) == 0) {
return count;
} else {
if (n.getLeftTree() != null) {
t.push(n.getLeftTree());
count++;
}
if (n.getRightTree() != null) {
t.push(n.getRightTree());
count++;
}
}
}
}
return -1;
}
However the algorithm seems not to be counting the leftish part of the tree upto the found element. However if position is not the index in the sorted elements, that might be okay. (I did not check the correctness, as there is no early < check.) If this was a home work assignment, "non-recursive with stack," rework a recursive version. Probably two nested loops, and a comparison on -1 and +1.

Finding if a number is equal to sum of 2 nodes in a binary search tree

Here is my code that for this. I am traversing the whole tree and then doing a find on each node. find() takes O(log n), and so the whole program takes O(n log n) time.
Is there a better way to implement this program? I am not just talking of better in terms of time complexity but in general as well. How best to implement this?
public boolean searchNum(BinTreeNode node, int num) {
//validate the input
if (node == null) {
return false;
}
// terminal case for recursion
int result = num - node.item;
//I have a separate find() which finds if the key is in the tree
if (find(result)) {
return true;
}
return seachNum(node.leftChild, num) || searchNum(node.rightChilde, num);
}
public boolean find(int key) {
BinTreeNode node = findHelper(key, root);
if (node == null) {
return false;
} else {
return true;
}
}
private BinTreeNode findHelper(int key, BinTreeNode node) {
if (node == null) {
return null;
}
if (key == node.item) {
return node;
} else if (key < node.item) {
return findHelper(key, node.leftChild);
} else {
return findHelper(key, node.rightChild);
}
}
Finding two nodes in binary search tree sum to some value can be done in the similar way of finding two elements in a sorted array that sums to the value.
In the case with an array sorted from small to large, you keep two pointers, one start from beginning, one start from the end. If the sum of the two elements pointed by the pointers is larger than the target, you move the right pointer to left by one, if the sum is smaller than target, you move the left pointer to right by one. Eventually the two pointer will either points to two elements that sum to the target value, or meet in the middle.
boolean searchNumArray(int[] arr, int num) {
int left = 0;
int right = arr.length - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == num) {
return true;
} else if (sum > num) {
right--;
} else {
left++;
}
}
return false;
}
If you do an in-order traversal of the binary search tree, it becomes a sorted array. So you can apply the same idea on binary search tree.
The following code do iterative in-order traversal from both directions. Stack is being used for the traversal, so the time complexity is O(n) and space complexity is O(h), where h is the height of the binary tree.
class BinTreeIterator implements Iterator<BinTreeNode> {
Stack<BinTreeNode> stack;
boolean leftToRight;
public boolean hasNext() {
return !stack.empty();
}
public BinTreeNode next() {
return stack.peek();
}
public void remove() {
BinTreeNode node = stack.pop();
if (leftToRight) {
node = node.rightChild;
while (node.rightChild != null) {
stack.push(node);
node = node.rightChild;
}
} else {
node = node.leftChild;
while (node.leftChild != null) {
stack.push(node);
node = node.leftChild;
}
}
}
public BinTreeIterator(BinTreeNode node, boolean leftToRight) {
stack = new Stack<BinTreeNode>();
this.leftChildToRight = leftToRight;
if (leftToRight) {
while (node != null) {
stack.push(node);
node = node.leftChild;
}
} else {
while (node != null) {
stack.push(node);
node = node.rightChild;
}
}
}
}
public static boolean searchNumBinTree(BinTreeNode node, int num) {
if (node == null)
return false;
BinTreeIterator leftIter = new BinTreeIterator(node, true);
BinTreeIterator rightIter = new BinTreeIterator(node, false);
while (leftIter.hasNext() && rightIter.hasNext()) {
BinTreeNode left = leftIter.next();
BinTreeNode right = rightIter.next();
int sum = left.item + right.item;
if (sum == num) {
return true;
} else if (sum > num) {
rightIter.remove();
if (!rightIter.hasNext() || rightIter.next() == left) {
return false;
}
} else {
leftIter.remove();
if (!leftIter.hasNext() || leftIter.next() == right) {
return false;
}
}
}
return false;
}
Chen Pang has already given a perfect answer. However, I was trying the same problem today and I could come up with the following solution. Posting it here as it might help some one.
The idea is same as that of earlier solution, just that I am doing it with two stacks - one following the inorder(stack1) and another following reverse - inorder order(stack2). Once we reach the left-most and the right-most node in a BST, we can start comparing them together.
If the sum is less than the required value, pop out from stack1, else pop from stack2. Following is java implementation of the same:
public int sum2(TreeNode A, int B) {
Stack<TreeNode> stack1 = new Stack<>();
Stack<TreeNode> stack2 = new Stack<>();
TreeNode cur1 = A;
TreeNode cur2 = A;
while (!stack1.isEmpty() || !stack2.isEmpty() ||
cur1 != null || cur2 != null) {
if (cur1 != null || cur2 != null) {
if (cur1 != null) {
stack1.push(cur1);
cur1 = cur1.left;
}
if (cur2 != null) {
stack2.push(cur2);
cur2 = cur2.right;
}
} else {
int val1 = stack1.peek().val;
int val2 = stack2.peek().val;
// need to break out of here
if (stack1.peek() == stack2.peek()) break;
if (val1 + val2 == B) return 1;
if (val1 + val2 < B) {
cur1 = stack1.pop();
cur1 = cur1.right;
} else {
cur2 = stack2.pop();
cur2 = cur2.left;
}
}
}
return 0;
}
As far as I know, O(log n) is the best possible searching function you can use. I'm interested in the "n". If you're using a for-loop somewhere, consider using a hashtable in its stead. Hash table seeking is O(1) if I recall correctly.
From http://www.geeksforgeeks.org/find-a-pair-with-given-sum-in-bst/
/* In a balanced binary search tree isPairPresent two element which sums to
a given value time O(n) space O(logn) */
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
// A BST node
struct node
{
int val;
struct node *left, *right;
};
// Stack type
struct Stack
{
int size;
int top;
struct node* *array;
};
// A utility function to create a stack of given size
struct Stack* createStack(int size)
{
struct Stack* stack =
(struct Stack*) malloc(sizeof(struct Stack));
stack->size = size;
stack->top = -1;
stack->array =
(struct node**) malloc(stack->size * sizeof(struct node*));
return stack;
}
// BASIC OPERATIONS OF STACK
int isFull(struct Stack* stack)
{ return stack->top - 1 == stack->size; }
int isEmpty(struct Stack* stack)
{ return stack->top == -1; }
void push(struct Stack* stack, struct node* node)
{
if (isFull(stack))
return;
stack->array[++stack->top] = node;
}
struct node* pop(struct Stack* stack)
{
if (isEmpty(stack))
return NULL;
return stack->array[stack->top--];
}
// Returns true if a pair with target sum exists in BST, otherwise false
bool isPairPresent(struct node *root, int target)
{
// Create two stacks. s1 is used for normal inorder traversal
// and s2 is used for reverse inorder traversal
struct Stack* s1 = createStack(MAX_SIZE);
struct Stack* s2 = createStack(MAX_SIZE);
// Note the sizes of stacks is MAX_SIZE, we can find the tree size and
// fix stack size as O(Logn) for balanced trees like AVL and Red Black
// tree. We have used MAX_SIZE to keep the code simple
// done1, val1 and curr1 are used for normal inorder traversal using s1
// done2, val2 and curr2 are used for reverse inorder traversal using s2
bool done1 = false, done2 = false;
int val1 = 0, val2 = 0;
struct node *curr1 = root, *curr2 = root;
// The loop will break when we either find a pair or one of the two
// traversals is complete
while (1)
{
// Find next node in normal Inorder traversal. See following post
// http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/
while (done1 == false)
{
if (curr1 != NULL)
{
push(s1, curr1);
curr1 = curr1->left;
}
else
{
if (isEmpty(s1))
done1 = 1;
else
{
curr1 = pop(s1);
val1 = curr1->val;
curr1 = curr1->right;
done1 = 1;
}
}
}
// Find next node in REVERSE Inorder traversal. The only
// difference between above and below loop is, in below loop
// right subtree is traversed before left subtree
while (done2 == false)
{
if (curr2 != NULL)
{
push(s2, curr2);
curr2 = curr2->right;
}
else
{
if (isEmpty(s2))
done2 = 1;
else
{
curr2 = pop(s2);
val2 = curr2->val;
curr2 = curr2->left;
done2 = 1;
}
}
}
// If we find a pair, then print the pair and return. The first
// condition makes sure that two same values are not added
if ((val1 != val2) && (val1 + val2) == target)
{
printf("\n Pair Found: %d + %d = %d\n", val1, val2, target);
return true;
}
// If sum of current values is smaller, then move to next node in
// normal inorder traversal
else if ((val1 + val2) < target)
done1 = false;
// If sum of current values is greater, then move to next node in
// reverse inorder traversal
else if ((val1 + val2) > target)
done2 = false;
// If any of the inorder traversals is over, then there is no pair
// so return false
if (val1 >= val2)
return false;
}
}
// A utility function to create BST node
struct node * NewNode(int val)
{
struct node *tmp = (struct node *)malloc(sizeof(struct node));
tmp->val = val;
tmp->right = tmp->left =NULL;
return tmp;
}
// Driver program to test above functions
int main()
{
/*
15
/ \
10 20
/ \ / \
8 12 16 25 */
struct node *root = NewNode(15);
root->left = NewNode(10);
root->right = NewNode(20);
root->left->left = NewNode(8);
root->left->right = NewNode(12);
root->right->left = NewNode(16);
root->right->right = NewNode(25);
int target = 28;
if (isPairPresent(root, target) == false)
printf("\n No such values are found\n");
getchar();
return 0;
}
I found one bug under Chen Pang answer otherwise it's perfect. Bug is under remove method. All other code is same except remove method under iterator
suppose we have tree, per Chen Pang answer its will not consider element 18. similarly for left iterator
10
20
15 25
13 18
class BinTreeIterator implements Iterator<BinTreeNode> {
Stack<BinTreeNode> stack;
boolean leftToRight;
public boolean hasNext() {
return !stack.empty();
}
public BinTreeNode next() {
return stack.peek();
}
public void remove() {
BinTreeNode node = stack.pop();
if (leftToRight) {
node = node.rightChild;
while (node.rightChild != null) {
stack.push(node);
BinTreeNode leftNode=node.leftChild;
while (leftNode != null) {
stack.push(leftNode);
leftNode= node.leftChild;
}
node = node.rightChild;
}
} else {
node = node.leftChild;
while (node.leftChild != null) {
stack.push(node);
BinTreeNode rightNode=node.rightChild;
while (rightNode != null) {
stack.push(rightNode);
rightNode= node.rightChild;
}
node = node.leftChild;
}
}
}
public BinTreeIterator(BinTreeNode node, boolean leftToRight) {
stack = new Stack<BinTreeNode>();
this.leftToRight = leftToRight;
if (leftToRight) {
while (node != null) {
stack.push(node);
node = node.leftChild;
}
} else {
while (node != null) {
stack.push(node);
node = node.rightChild;
}
}
}
public static boolean searchNumBinTree(BinTreeNode node, int num) {
if (node == null)
return false;
BinTreeIterator leftIter = new BinTreeIterator(node,true);
BinTreeIterator rightIter = new BinTreeIterator(node,false);
while (leftIter.hasNext() && rightIter.hasNext()) {
BinTreeNode left = leftIter.next();
BinTreeNode right = rightIter.next();
int sum = left.item + right.item;
if (sum == num) {
return true;
} else if (sum > num) {
rightIter.remove();
if (!rightIter.hasNext() || rightIter.next() == left) {
return false;
}
} else {
leftIter.remove();
if (!leftIter.hasNext() || leftIter.next() == right) {
return false;
}
}
}
return false;
}
private static class BinTreeNode{
BinTreeNode leftChild;
BinTreeNode rightChild;
}
}
public boolean nodeSum(Node root, int num){
/*
Just subtract the sum from current value of the node and find
the node with remainder.
*/
if(root==null){
return false;
}
int val=num-root.key;
boolean found=find(root,val);
if(found){
return true;
}
boolean lSum=nodeSum(root.left,num);
boolean rSum=nodeSum(root.right,num);
return lSum||rSum;
}
public boolean find(Node root, int k){//same as search
if(root==null){
return false;
}
if(root.key==k){
return true;
}
if(root.key<k){
return find(root.right,k);
}else{
return find(root.left, k);
}
}

Red Black Tree Top-Down Deletion Algorithm

I am implementing a Red Black Tree with insert, search and delete functions in O (log n) time. Insert and search are working fine. However I am stuck on delete. I found this ppt slide on the internet which shows the algorithm of RBT deletion: http://www.slideshare.net/piotrszymanski/red-black-trees#btnNext on page 56 onwards. I know I am asking a bit too much but I have been stuck on this for over 2 weeks and I can't find the problem. The way I'm understanding Top-Down deletion that you have to rotate and recolor nodes accordingly until you find the predecessor of the node to be deleted. When you do find this node - which would be either a leaf or a node with one right child, replace node to be deleted data by the data of this node and delete this node like normal BST deletion, right?
This is the code I did, based on what I learnt from that slide. If anyone would be so kind to go over it, I would be more than grateful! Or at least if you think there's a better algorithm than what I'm using, please tell me!
public void delete(int element){
if (root == null){
System.out.println("Red Black Tree is Empty!");
} else {
Node X = root;
parent = null;
grandParent = null;
sibling = null;
if (isLeaf(X)){
if (X.getElement() == element){
emptyRBT();
}
} else {
if (checkIfBlack(root.getLeftChild()) && checkIfBlack(root.getRightChild())){
root.setIsBlack(false);
if (X.getElement() > element && X.getLeftChild() != null){
X = moveLeft(X);
} else if (X.getElement() < element && X.getRightChild() != null){
X = moveRight(X);
}
Step2(X, element);
} else {
Step2B(X, element);
}
}
}
root.setIsBlack(true);
}
public void Step2(Node X, int element)
{
int dir = -1;
while (!isLeaf(X)){
if (predecessor == null){ // still didn't find Node to delete
if (X.getElement() > element && X.getLeftChild() != null){
X = moveLeft(X);
dir = 0;
} else if (X.getElement() < element && X.getRightChild() != null){
X = moveRight(X);
dir = 1;
} else if (X.getElement() == element){
toDelete = X;
predecessor = inorderPredecessor(X.getRightChild());
X = moveRight(X);
}
} else { // if node to delete is already found and X is equal to right node of to delete
// move always to the left until you find predecessor
if (X != predecessor){
X = moveLeft(X);
dir = 0;
}
}
if (!isLeaf(X)){
if (!hasOneNullNode(X)){
if (checkIfBlack(X.getLeftChild()) && checkIfBlack(X.getRightChild())){
Step2A(X, element, dir);
} else {
Step2B(X, element);
}
}
}
}
removeNode(X);
if (predecessor != null){
toDelete.setElement(X.getElement());
}
}
public Node Step2A(Node X, int element, int dir) {
if (checkIfBlack(sibling.getLeftChild()) && checkIfBlack(sibling.getRightChild())) {
X = Step2A1(X);
} else if ((checkIfBlack(sibling.getLeftChild()) == false) && checkIfBlack(sibling.getRightChild())) {
X = Step2A2(X);
} else if ((checkIfBlack(sibling.getLeftChild()) && (checkIfBlack(sibling.getRightChild()) == false))) {
X = Step2A3(X);
} else if ((checkIfBlack(sibling.getLeftChild()) == false) && (checkIfBlack(sibling.getRightChild()) == false)) {
X = Step2A3(X);
}
return X;
}
public Node Step2A1(Node X) {
X.setIsBlack(!X.IsBlack());
parent.setIsBlack(!parent.IsBlack());
sibling.setIsBlack(!sibling.IsBlack());
return X;
}
public Node Step2A2(Node X) {
if (parent.getLeftChild() == sibling){
LeftRightRotation(sibling.getLeftChild(), sibling, parent);
} else RightLeftRotation(sibling.getRightChild(), sibling, parent);
X.setIsBlack(!X.IsBlack());
parent.setIsBlack(!parent.IsBlack());
return X;
}
public Node Step2A3(Node X) {
if (parent.getLeftChild() == sibling){
leftRotate(sibling);
} else if (parent.getRightChild() == sibling){
rightRotate(sibling);
}
X.setIsBlack(!X.IsBlack());
parent.setIsBlack(!parent.IsBlack());
sibling.setIsBlack(!sibling.IsBlack());
sibling.getRightChild().setIsBlack(!sibling.getRightChild().IsBlack());
return X;
}
public void Step2B(Node X, int element){
if (predecessor == null){
if (X.getElement() > element && X.getLeftChild() != null){
X = moveLeft(X);
} else if (X.getElement() < element && X.getRightChild() != null){
X = moveRight(X);
} else if (X.getElement() == element){
Step2(X, element);
}
} else {
if (X != predecessor)
X = moveLeft(X);
else Step2(X, element);
}
if (X.IsBlack()){
if (parent.getLeftChild() == sibling){
leftRotate(sibling);
} else if (parent.getRightChild() == sibling){
rightRotate(sibling);
}
parent.setIsBlack(!parent.IsBlack());
sibling.setIsBlack(!sibling.IsBlack());
Step2(X, element);
} else {
Step2B(X, element);
}
}
public void removeNode(Node X) {
if (isLeaf(X)) {
adjustParentPointer(null, X);
count--;
} else if (X.getLeftChild() != null && X.getRightChild() == null) {
adjustParentPointer(X.getLeftChild(), X);
count--;
} else if (X.getRightChild() != null && X.getLeftChild() == null) {
adjustParentPointer(X.getRightChild(), X);
count--;
}
}
public Node inorderPredecessor(Node node){
while (node.getLeftChild() != null){
node = node.getLeftChild();
}
return node;
}
public void adjustParentPointer(Node node, Node current) {
if (parent != null) {
if (parent.getElement() < current.getElement()) {
parent.setRightChild(node);
} else if (parent.getElement() > current.getElement()) {
parent.setLeftChild(node);
}
} else {
root = node;
}
}
public boolean checkIfBlack(Node n){
if (n == null || n.IsBlack() == true){
return true;
} else return false;
}
public Node leftRotate(Node n)
{
parent.setLeftChild(n.getRightChild());
n.setRightChild(parent);
Node gp = grandParent;
if (gp != null){
if (gp.getElement() > n.getElement()){
gp.setLeftChild(n);
} else if (gp.getElement() < n.getElement()){
gp.setRightChild(n);
}
} else root = n;
return n;
}
public Node rightRotate(Node n)
{
parent.setRightChild(n.getLeftChild());
n.setLeftChild(parent);
Node gp = grandParent;
if (gp != null){
if (gp.getElement() > n.getElement()){
gp.setLeftChild(n);
} else if (gp.getElement() < n.getElement()){
gp.setRightChild(n);
}
} else root = n;
return n;
}
The node is being deleted, but the tree after deletion would be black violated, which is very wrong.
The eternally confuzzled blog has top-down implementations of both insert and delete for red-black trees. It also goes through case-by-case why it works. I won't replicate it here (it's rather lengthy).
I've used that blog as a reference for implementing red-black trees in both c++ and java. As I discussed in an earlier answer, I found the implementation to be faster than std::map's bottom-up implementation of red-black trees (whatever STL came with gcc at the time).
Here's an untested, direct translation of the code to Java. I would highly suggest you test it and morph it to match your style.
private final static int LEFT = 0;
private final static int RIGHT = 1;
private static class Node {
private Node left,right;
private boolean red;
...
// any non-zero argument returns right
Node link(int direction) {
return (direction == LEFT) ? this.left : this.right;
}
// any non-zero argument sets right
Node setLink(int direction, Node n) {
if (direction == LEFT) this.left = n;
else this.right = n;
return n;
}
}
boolean remove(int data) {
if ( this.root != null ) {
final Node head = new Node(-1, null, null); /* False tree root */
Node cur, parent, grandpa; /* Helpers */
Node found = null; /* Found item */
int dir = RIGHT;
/* Set up helpers */
cur = head;
grandpa = parent = null;
cur.setLink(RIGHT, this.root);
/* Search and push a red down */
while ( cur.link(dir) != null ) {
int last = dir;
/* Update helpers */
grandpa = parent, parent = cur;
cur = cur.link(dir);
dir = cur.data < data ? RIGHT : LEFT;
/* Save found node */
if ( cur.data == data )
found = cur;
/* Push the red node down */
if ( !is_red(cur) && !is_red(cur.link(dir)) ) {
if ( is_red(cur.link(~dir)) )
parent = parent.setLink(last, singleRotate(cur, dir));
else if ( !is_red(cur.link(~dir)) ) {
Node s = parent.link(~last);
if ( s != null ) {
if (!is_red(s.link(~last)) && !is_red(s.link(last))) {
/* Color flip */
parent.red = false;
s.red = true;
cur.red = true;
}
else {
int dir2 = grandpa.link(RIGHT) == parent ? RIGHT : LEFT;
if ( is_red(s.link(last)) )
grandpa.setLink(dir2, doubleRotate(parent, last));
else if ( is_red(s.link(~last)) )
grandpa.setLink(dir2, singleRotate(parent, last));
/* Ensure correct coloring */
cur.red = grandpa.link(dir2).red = true;
grandpa.link(dir2).link(LEFT).red = false;
grandpa.link(dir2).link(RIGHT).red = false;
}
}
}
}
}
/* Replace and remove if found */
if ( found != null ) {
found.data = cur.data;
parent.setLink(
parent.link(RIGHT) == cur ? RIGHT : LEFT,
cur.link(cur.link(LEFT) == null ? RIGHT : LEFT));
}
/* Update root and make it black */
this.root = head.link(RIGHT);
if ( this.root != null )
this.root.red = false;
}
return true;
}
quick link :
http://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html
--> Caution : the code on the site is relying on two jars. In the datastructures however the dependency might be minimal. Sometimes it's enough to comment out the main method (that only serves as a test client)
If not : the jars are downloadable on the same site.
If you are looking for two weeks and studying algoritms, chances are you know about
http://algs4.cs.princeton.edu/
the website that is accompanying the famous
Algorithms, by Robert Sedgewick and Kevin Wayne
book.
On this website, there is this implementation of a red black (balances) tree :
http://algs4.cs.princeton.edu/33balanced/RedBlackBST.java.html
I didnot look into it yet (I will later on this year) , but I fully trust it to be a working implementation of a RBTree.
Some sidenote that might be interesting for visitors of this topic:
MIT placed excellent courses concerning algoritms online. The one concerning rbtrees is
http://www.youtube.com/watch?v=iumaOUqoSCk

Categories