Related
I'm trying to determine if one tree (t) is a subtree of another tree (s).
This is a link to the leetcode which explains the problem thoroughly:https://leetcode.com/problems/subtree-of-another-tree/
My approach: I have one function that does a dfs on s and compares each node to the root of t in another function to determine if t is a subtree of s
My solution doesn't work for when s=[1,1] and t=[1], although I think it should be working. Could you please look at my code and explain what's wrong.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSubtree(TreeNode s, TreeNode t) {
/* dfs on s, at each node running a compare tree function for s at that node and
root of t*/
if(s == null || t == null) {
return false;
}
return dfs(s, t);
}
public static boolean dfs(TreeNode s, TreeNode t) {
if(s == null) {
return false;
}
if(s.val == t.val) {
return isSameTree(s, t);
}
return dfs(s.left, t) || dfs(s.right, t);
}
public static boolean isSameTree(TreeNode s, TreeNode t) {
if(s == null || t == null) {
return s == t;
}
if(s.val != t.val) {
return false;
}
return isSameTree(s.left, t.left) && isSameTree(s.right, t.right);
}
}
You need to check for all nodes of s if t is a subtree of that node or not. If you stop at first node while performing dfs on s and its value is same as root of t but subtrees are different, there might be some another node of tree s whose value and subtree both are same as t.
In other words, you need to repeat your 1st step (perform dfs on s and compare each node of s to the root of t) until you have checked all nodes of s (dfs is complete on s) or found that t is subtree of s.
s t
(1) (1)
/
(1)
Do not return from root of s just because of same values of root of s and t. If t is not subtree of that node, keep doing dfs to find another node whose value and subtree both are same as t (left child of root of s in this case).
For more clarity, below is your code with corrected part highlighted:
class Solution {
public boolean isSubtree(TreeNode s, TreeNode t) {
/* dfs on s, at each node running a compare tree function for s at that node and
root of t*/
if(s == null || t == null) {
return false;
}
return dfs(s, t);
}
public static boolean dfs(TreeNode s, TreeNode t) {
if(s == null) {
return false;
}
// ==== Corrected below if ====
// apart from s.val == t.val, if isSameTree(s, t) is true at this
// point, return true; otherwise keep doing dfs for rest of the tree s
// other same value node of s can be the answer
if(s.val == t.val && isSameTree(s, t)) {
return true;
}
return dfs(s.left, t) || dfs(s.right, t);
}
public static boolean isSameTree(TreeNode s, TreeNode t) {
if(s == null || t == null) {
return s == t;
}
if(s.val != t.val) {
return false;
}
return isSameTree(s.left, t.left) && isSameTree(s.right, t.right);
}
}
Looks pretty good! Almost there!
This'd pass:
public class Solution {
public static final boolean isSubtree(
final TreeNode s,
final TreeNode t
) {
if (s == null) {
return false;
}
if (checkNextLevel(s, t)) {
return true;
}
return isSubtree(s.left, t) ||
isSubtree(s.right, t);
}
private static final boolean checkNextLevel(
final TreeNode s,
final TreeNode t
) {
if (s == null && t == null) {
return true;
}
if (
(s == null || t == null) ||
(s.val != t.val)
) {
return false;
}
return checkNextLevel(s.left, t.left) &&
checkNextLevel(s.right, t.right);
}
}
node root=null;
public node delete(node node, int val) {
if(node == null) {
return node;
}
if(val < node.value) {
node.left= delete(node.left, val);
} else if(val > node.value) {
node.right= delete(node.right, val);
} else {
if(node.left== null || node.right== null) {
node temp = node.left!= null ? node.left: node.right;
if(temp == null) {
return null;
} else {
return temp;
}
} else {
node next = getSuccessor(node);
node.value= next.value;
node.right= delete(node.right, next.value);
return node;
}
}
return node;
}
public node getSuccessor(node node) {
if(node == null) {
return null;
}
node temp = node.right;
while(temp.left!= null) {
temp = temp.left;
}
return temp;
}
this is my code
and this is the class for the nodes:
public class node {
int value;
node left;
node right;
}
I already have a working code to add values.
the problem is, when i add values, and try to delete some of them with the code i just wrote here, it's not working.
this is what i put in main class when i try to delete a value:
binarytree tree= new binarytree;
node root=null;
root=tree.delete(root,4);
does anyone have any idea what could be wrong?
am i missing a function that refers to the delete one or something like that?
please note i'm new to java so if you want to help me treat me as a beginner
i'd really appreciate if someone could help me make my delete function work because now it's not doing anything at all...
EDIT:
Code to add values:
void recadd(node a, int val) {
if (val<a.value) {
if (a.left==null){
a.left=new node (val);
}
}
else
{
if(a.right==null) {
a.right=new node(val);
}
else {
recadd(a.right, val);
}
}
}
the code i use to call the add function:
void add(int val){
node k = new node (val);
if (root==null)
{
root = k;
}
else
{
recadd(root, val);
}
}
as stated before, i can add values just fine, the problem occurs when i try to delete them.
Your code should work. Maybe something is wrong with how you are inserting elements. Can you please share your full code?
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?
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);
}
}
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