I've spent about two days pouring over this and I have no idea what's missing. Originally my BST used comparables, then I switched it to int to simplify it when it wasn't working.
I add several items to a tree and it successfully prints them out in order. Then, the first time I call the search() method it returns true, as it should. Every other search call after that returns false whether it is true or false.
I'm including most of my code here in case the problem isn't related with the search method itself.
The output SHOULD be: 4 12 23 27 30 42 60 84 true true false true true
but instead I get: 4 12 23 27 30 42 60 84 true false false false false
public class BSTree {
TreeNode root;
static int comparison;
public void insert(int value) {
if (root == null) {
root = new TreeNode(value);
}
else {
root.insert(value);
}
}
public boolean search(int chicken) {
if (root != null ) {
return root.search(chicken);
}
return false;
}
public static int height(TreeNode b) {
return TreeNode.height(b);
}
public static void CompareSet() {
comparison++;
}
public int getCompare() {
return comparison;
}
public void ResetCompare() {
comparison = 0;
}
public static void traverseInOrder (TreeNode node) {
if (node != null) {
traverseInOrder(node.left);
System.out.print(" " + node.data);
traverseInOrder (node.right);
}
}
public static void main(String args[]) {
BSTree tree = new BSTree();
tree.insert(30);
tree.insert(42);
tree.insert(84);
tree.insert(12);
tree.insert(4);
tree.insert(23);
tree.insert(27);
tree.insert(60);
traverseInOrder(tree.root);
System.out.println("\n" + tree.search(30));
System.out.println("\n" + tree.search(4));
System.out.println("" + tree.search(50));
System.out.println("" + tree.search(27));
System.out.println("" + tree.search(42));
System.out.println(height(tree.root));
}
}
Here is the treeNode class:
public class TreeNode<T> {
int data;
TreeNode left;
TreeNode right;
TreeNode(int value){
this.data = value;
//right = null;
//left = null;
}
public void insert(int value) {
if (value == data) {
return;
}
if (value < data) {
if (left == null) {
left = new TreeNode(value);
}
else {
left.insert(value);
}
}
else {
if (right == null) {
right = new TreeNode(value);
}
else {
right.insert(value);
}
}
public boolean search(int value) {
BSTree.CompareSet();
if (data == value) return true;
if (data < value && left!=null)
return left.search(value);
else if(data > value && right != null)
return right.search(value);
return false;
}
public static int height(TreeNode b) {
if (b == null) return -1;
return 1 + Math.max(height(b.left), height(b.right));
}
public int getData(){
return data;
}
public TreeNode getLeftChild() {
return left;
}
public void setLeftChild(TreeNode leftChild) {
this.left = leftChild;
}
public TreeNode getRightChild() {
return right;
}
public void setRightChild(TreeNode rightChild) {
this.right = rightChild;
}
}
Your comparaisons are reversed :))) Here is the corrected TreeNode::search method :
public boolean search(int value) {
BSTree.CompareSet();
if (data == value) return true;
if (data > value && left!=null)
return left.search(value);
else if(data < value && right != null)
return right.search(value);
return false;
}
I think you swapped the data and the value variables.
just change your search method of TreeNode class to this:
public boolean search(int value) {
Test.CompareSet();
if (data == value) return true;
if (data < value && right!=null)
return right.search(value);
else if(data > value && left != null)
return left.search(value);
return false;
}
When your current node's data is greater than value you need to go to left sub-tree. And when current node's data is smaller than value you need to go to right sub-tree. You just have done the reverse one.
Related
I have the following code.
But it is expected to be without parameters for example sum() and i am not quite sure on how to fix that so that the code would still work. Could someone help me with that?
I would like change the code as little as possible.
is there a way to add it to the methods and the recall the recusive methods from that
import java.util.*;
public class BinarySearchTree {
private class BinaryNode {
private int element;
private BinaryNode left;
private BinaryNode right;
private BinaryNode(int element) {
this.element = element;
}
}
private BinaryNode root;
public void insert(int newNumber) {
// special case: empty tree
if (root == null) {
root = new BinaryNode(newNumber);
return;
}
BinaryNode parent = null;
BinaryNode child = root;
while (child != null) {
parent = child;
if (newNumber == child.element) {
//number already in tree
return;
} else if (newNumber < child.element) {
child = child.left;
} else {
child = child.right;
}
}
if (newNumber < parent.element) {
parent.left = new BinaryNode(newNumber);
} else {
parent.right = new BinaryNode(newNumber);
}
}
public int maximumRecursive(BinaryNode root) {
if (root.right == null)
return root.element;
return maximumRecursive(root.right);
}
public int maximumIterative() {
if (root == null) {
throw new NoSuchElementException();
}
BinaryNode current = root;
while (current.right != null)
current = current.right;
return (current.element);
}
public int height(BinaryNode root) {
if (root == null)
return 0;
return 1 + Math.max(height(root.left), height(root.right));
}
public int sum(BinaryNode root) {
if (root == null)
return 0;
return root.element + sum(root.left) + sum(root.right);
}
public String reverseOrder(BinaryNode root) {
if (root == null) {
return "";
}
return reverseOrder(root.right) + " " + ((Integer) root.element).toString() + " " + reverseOrder(root.left);
}
You can just overload your sum method, so you have the version with parameter, and without parameter. Make the one with parameter private, as that version should only be used during the recursive deepening (inside the class):
private int sum(BinaryNode root) {
if (root == null)
return 0;
return root.element + sum(root.left) + sum(root.right);
}
public int sum() {
return sum(root);
}
You can do a similar thing for the other methods that are recursive, and for that reason have a parameter. For instance, for height:
private int height(BinaryNode root) {
if (root == null)
return 0;
return 1 + Math.max(height(root.left), height(root.right));
}
public int height() {
return height(root);
}
Here is the Node class:
public class BSTNode<T extends Comparable<? super T>> {
private T data;
private BSTNode<T> left;
private BSTNode<T> right;
BSTNode(T data) {
this.data = data;
}
T getData() {
return data;
}
BSTNode<T> getLeft() {
return left;
}
BSTNode<T> getRight() {
return right;
}
void setData(T data) {
this.data = data;
}
void setLeft(BSTNode<T> left) {
this.left = left;
}
void setRight(BSTNode<T> right) {
this.right = right;
}
}
Here is my BST class with main driver method:
import java.util.NoSuchElementException;
public class BST<T extends Comparable<? super T>> {
private BSTNode<T> root;
private int size;
BST() {
root = null;
}
public void add(T data) {
if (data == null) {
throw new IllegalArgumentException("Error: Data can't be null");
}
root = rAdd(root, data);
}
private BSTNode<T> rAdd(BSTNode<T> current, T data) {
if (current == null) {
size++;
return new BSTNode<T>(data);
} else if (data.compareTo(current.getData()) < 0) {
current.setLeft(rAdd(current.getLeft(), data));
} else if (data.compareTo(current.getData()) > 0) {
current.setRight(rAdd(current.getRight(), data));
}
return current;
}
public T remove(T data) {
if (data == null) {
throw new IllegalArgumentException("Error: data can't be null");
}
BSTNode<T> dummy = new BSTNode<>(null);
root = rRemove(root, data, dummy);
return dummy.getData();
}
private BSTNode<T> rRemove(BSTNode<T> current, T data, BSTNode<T> dummy) {
if (current == null) {
throw new NoSuchElementException("Error: Data not present");
} else if (data.compareTo(current.getData()) < 0) {
current.setLeft(rRemove(current.getLeft(), data, dummy));
} else if (data.compareTo(current.getData()) > 0) {
current.setRight(rRemove(current.getRight(), data, dummy));
} else {
System.out.println("Data found ... ");
dummy.setData(current.getData());
size--;
if (current.getRight() == null && current.getLeft() == null) {
if (current.equals(root)) {
this.root = null;
}
return null;
} else if (current.getLeft() != null) {
return current.getLeft();
} else if (current.getRight() != null) {
return current.getRight();
} else {
BSTNode<T> dummy2 = new BSTNode<>(null);
current.setRight(removeSuccessor(current.getRight(), dummy2));
current.setData(dummy2.getData());
}
}
return current;
}
private BSTNode<T> removeSuccessor(BSTNode<T> current, BSTNode<T> dummy) {
if (current.getLeft() == null) {
dummy.setData(current.getData());
return current.getRight();
} else {
current.setLeft(removeSuccessor(current.getLeft(), dummy));
}
}
public List<T> inorder(BSTNode<T> root) {
ArrayList<T> inorderContents = new ArrayList<T>();
if (root == null) {
return inorderContents;
}
inorderR(inorderContents, root);
return inorderContents;
}
private void inorderR(ArrayList<T> inorderContents, BSTNode<T> current) {
if (current == null) {
return;
}
inorderR(inorderContents, current.getLeft());
inorderContents.add(current.getData());
inorderR(inorderContents, current.getRight());
}
public BSTNode<T> getRoot() {
// DO NOT MODIFY THIS METHOD!
return root;
}
public int size() {
// DO NOT MODIFY THIS METHOD!
return size;
}
public static void main(String[] args) {
BST bst3 = new BST<>();
bst3.add(1);
bst3.add(0);
bst3.add(5);
bst3.add(4);
bst3.add(2);
bst3.add(3);
System.out.println(bst3.inorder(bst3.getRoot() ));
bst3.remove(1);
System.out.println(bst3.inorder(bst3.getRoot() ));
}
}
My IDE (IntelliJ) says I am missing a return statement for my removeSuccessor(BSTNode current, BSTNode dummy) method but I expected it to recurse to the base case reinforcing the unchanged nodes.
As a result when I try and remove from a two child node it returns zero although the one child and zero child cases work .
Please can someone tell me what is wrong with my two child node remove case? Thanks, Sperling.
First, you need to modify the if-else by changing the conditions:
if (current.getLeft() != null && current.getRight() == null) {
return current.getLeft();
} else if (current.getRight() != null && current.getLeft() == null) {
return current.getRight();
}
instead of the same without the 2nd arguments of && in the rRemove() method.
Then, use this:
private BSTNode<T> removeSuccessor(BSTNode<T> current, BSTNode<T> dummy) {
if (current.getLeft() == null) {
dummy.setData(current.getData());
return current.getRight();
} else {
current.setLeft(removeSuccessor(current.getLeft(), dummy));
return current;
}
}
Meaning of this method is as follows: delete the lowest value in the tree and return new root, as well as remember the value using dummy.
If we get nothing to the left, it's trivial - we delete current node, return getRight() and set a value to dummy.
On the other hand, if we get something to the left then we know that our current node will be the root, but before we return it we need to remove the lowest entry to the left, and so we use the function recursively, also setting current.left to be it's return value to properly transform the tree. We pass dummy so that it can get a value when the first case occurs, and then it's communicated to the highest call (inside the first function).
It's also possible to do it without recursion:
private BSTNode<T> removeSuccessor2(BSTNode<T> current, BSTNode<T> dummy) {
BSTNode<T> root = current;
BSTNode<T> prev = null;
while(current.getLeft() != null) {
prev = current;
current = current.getLeft();
}
/* current.getLeft == null */
//we will delete current
if (prev == null) { //no loop iterations -- current is the root
dummy.setData(current.getData());
return(current.getRight());
}
else {//some iterations passed, prev.getLeft() == curret
dummy.setData(current.getData());
prev.setLeft(current.getRight());
return root;
}
}
With dummy we return the value, the rest is transforming the tree.
Note: It doesn't work in my version for current == null. You should be able to modify it easily, though. Also, for clarity I didn't pull the dummy.setData... before if...else etc. Modify it as you wish!
Trying to search the binary search tree but there seems I cannot figure out why the there statement is not working, the method calls for the input of a String, but it says that a Node is required. Any suggestions how to fix this?
Here is the Node Class:
public class Node
{
String key;
Node left, right;
public Node(String entry)
{
key = entry;
left = right = null;
}
public Node getLeft()
{
return left;
}
public Node getRight()
{
return right;
}
public String getKey(String entry)
{
if(this.key.equals(key))
{
return key;
}
if(entry.compareTo(this.key) < 0)
{
return left == null ? null : left.getKey(entry);
}
else
{
return right == null ? null : right.getKey(entry);
}
}
public void setLeft(Node left)
{
this.left = left;
}
public void setRight(Node right)
{
this.right = right;
}
}
Here is my Binary Search Tree:
public class BinarySearchTree
{
Node root;
public BinarySearchTree()
{
root = null;
}
public void insert(String key)
{
root = insertRec(root, key);
}
public Node insertRec(Node root, String key)
{
if(root == null)
{
root = new Node(key);
return root;
}
if(key.compareTo(root.toString()) == -1)
{
root.setLeft(insertRec(root.getLeft(), key));
}
else if(key.compareTo(root.toString()) == 1)
{
root.setRight(insertRec(root.getRight(), key));
}
return root;
}
public Node search(String key)
{
return root == null ? null : root.getKey(key);
}
public void printPostOrder(Node node)
{
if(node == null)
return;
printPostOrder(root.getLeft());
printPostOrder(node.getRight());
System.out.print(node.getKey() + ", ");
}
public void printInOrder(Node node)
{
if(node == null)
return;
printInOrder(node.getLeft());
System.out.print(node.getKey() + ", ");
printInOrder(node.getRight());
}
public void printPreOrder(Node node)
{
if(node == null)
return;
System.out.print(node.getKey() + ", ");
printPreOrder(node.getLeft());
printPreOrder(node.getRight());
}
public void printPostOrder()
{
printPostOrder(root);
}
public void printInOrder()
{
printInOrder(root);
}
public void printPreOrder()
{
printPreOrder(root);
}
}
Any and all help is much appreciated if you need more information please let me know.
whats up ?
your code is wrong in the class node in method getKey change your return String to Node and your if equals and return to this.
Ex:.
public Node getKey(String entry)
{
if(this.key.equals(entry))
{
return this;
}
}
if you change this your code work.
Full class BinarySearchTree tested ok
public class BinarySearchTree
{
Node root;
public BinarySearchTree()
{
root = null;
}
public void insert(String key)
{
root = insertRec(root, key);
}
public Node insertRec(Node root, String key)
{
if(root == null)
{
root = new Node(key);
return root;
}
if(key.compareTo(root.toString()) == -1)
{
root.setLeft(insertRec(root.getLeft(), key));
}
else if(key.compareTo(root.toString()) == 1)
{
root.setRight(insertRec(root.getRight(), key));
}
return root;
}
public Node search(String key)
{
return root == null ? null : root.getKey(key);
}
public void printPostOrder(Node node)
{
if(node == null)
return;
printPostOrder(root.getLeft());
printPostOrder(node.getRight());
System.out.print(node.getKey("") + ", ");
}
public void printInOrder(Node node)
{
if(node == null)
return;
printInOrder(node.getLeft());
System.out.print(node.getKey("") + ", ");
printInOrder(node.getRight());
}
public void printPreOrder(Node node)
{
if(node == null)
return;
System.out.print(node.getKey("") + ", ");
printPreOrder(node.getLeft());
printPreOrder(node.getRight());
}
public void printPostOrder()
{
printPostOrder(root);
}
public void printInOrder()
{
printInOrder(root);
}
public void printPreOrder()
{
printPreOrder(root);
}
public static void main (String args[]){
BinarySearchTree bs = new BinarySearchTree();
bs.insert("A");
bs.search("A");
}
}
and Node complete
public class Node
{
String key;
Node left, right;
public Node(String entry)
{
key = entry;
left = right = null;
}
public Node getLeft()
{
return left;
}
public Node getRight()
{
return right;
}
public Node getKey(String entry)
{
if(this.key.equals(key))
{
return this;
}
if(entry.compareTo(this.key) < 0)
{
return left == null ? null : left.getKey(entry);
}
else
{
return right == null ? null : right.getKey(entry);
}
}
public void setLeft(Node left)
{
this.left = left;
}
public void setRight(Node right)
{
this.right = right;
}
}
I'm trying to implement a Dictionary using a Red-Black tree.
I've tested the insert method and it seems to work good, the RBtree seems to keep the correct shape and colors. The method that performs the binary tree node deletion seems to be correct, but I'm having huge problems on the deleteFixUp method called at the end of the deletion.
Would you like to help me figure out what I'm doing wrong? And, of course, if you have any suggestion to improve my code it would be very appreciated.
RBTreeWParentDictionary.java (Here I implemented the RedBlackTree)
package dictionary;
import java.util.Comparator;
public class RBTreeWParentDictionary<K, V> implements IDictionary<K, V> {
/**
* The root node of the RBTreeWParentDictionary
*/
public RBTreeWParentNode<K, V> root;
/**
* Object used to compare two T objects.
*/
private Comparator<K> comparator;
private int length;
/**
* Creates the dictionary based on red/black tree with null root
*
* #param comparator
* The comparator for keys
*/
public RBTreeWParentDictionary(Comparator<K> comparator) {
this.root = null;
this.comparator = comparator;
this.length = 0;
}
/**
* Checks if the tree is empty
*
* #return True if the tree is empty
*/
public boolean isEmpty() {
return this.root == null;
}
/**
* Returns the number of elements in the tree
*
* #return The number of elements in the tree
*/
public int length() {
return this.length;
}
/**
* Performs a left rotation on the tree node
*
* #param node
* The node on which rotate
*/
private void rotateLeft(RBTreeWParentNode<K, V> node) {
RBTreeWParentNode<K, V> y = node.getRight();
node.setRight(y.getLeft());
if (y.hasLeft()) {
y.getLeft().setParent(node);
}
y.setParent(node.getParent());
if (!node.hasParent()) { // = this.isEmpty()
this.root = y;
}
else {
if (node.equals(node.getParent().getLeft())) {
node.getParent().setLeft(y);
}
else {
node.getParent().setRight(y);
}
}
y.setLeft(node);
}
/**
* Performs a right rotation on the tree node
*
* #param node
* The node on which rotate
*/
private void rotateRight(RBTreeWParentNode<K, V> node) {
RBTreeWParentNode<K, V> y = node.getLeft();
node.setLeft(y.getRight());
if (y.hasRight()) {
y.getRight().setParent(node);
}
y.setParent(node.getParent());
if (!node.hasParent()) {
this.root = y;
}
else {
if (node.equals(node.getParent().getRight())) {
node.getParent().setRight(y);
}
else {
node.getParent().setLeft(y);
}
}
y.setRight(node);
}
/*
* Uses for first tests, now removed
*
* public void testRotateLeft() { this.rotateLeft(this.root); }
*
* public void testRotateRight() { this.rotateRight(this.root); }
*/
/**
* Performs all the needed work to the tree under the 3 main rules of R/BTree
*
* #param node
* The current node that needs to be checked
*/
private void treeFixUp(RBTreeWParentNode<K, V> node) {
RBTreeWParentNode<K, V> u;
if (!node.hasParent()) {
return;
}
while (node.getParent().isRed()) {
if (node.getParent().equals(node.getParent().getParent().getLeft())) {
u = node.getParent().getParent().getRight();
if (u != null && u.isRed()) {
node.getParent().setBlack();
u.setBlack();
node.getParent().getParent().setRed();
node = node.getParent().getParent();
}
else {
if (node.equals(node.getParent().getRight())) {
node = node.getParent();
rotateLeft(node);
}
node.getParent().setBlack();
node.getParent().getParent().setRed();
rotateRight(node.getParent().getParent());
}
}
else {
u = node.getParent().getParent().getLeft();
if (u != null && u.isRed()) {
node.getParent().setBlack();
u.setBlack();
node.getParent().getParent().setRed();
node = node.getParent().getParent();
}
else {
if (node.equals(node.getParent().getLeft())) {
node = node.getParent();
rotateRight(node);
}
node.getParent().setBlack();
node.getParent().getParent().setRed();
rotateLeft(node.getParent().getParent());
}
}
if (!node.hasParent()) {
node.setBlack();
break;
}
}
}
/**
* Inserts a node with give key/value
*
* #param key
* The key of the node to be inserted
* #param value
* The value of the node to be inserted
*/
#Override
public void insert(K key, V value) {
int res;
RBTreeWParentNode<K, V> insertedNode = new RBTreeWParentNode<K, V>(key,
value);
if (this.isEmpty()) {
this.root = insertedNode;
this.root.setBlack();
}
else {
RBTreeWParentNode<K, V> node = this.root;
while (node != null) {
res = comparator.compare(key, node.getKey());
if (res < 0) {
if (node.hasLeft()) {
node = node.getLeft();
}
else break;
}
else if (res > 0) {
if (node.hasRight()) {
node = node.getRight();
}
else break;
}
else { // duplicate key, overwriting
node.setValue(value);
return;
}
}
res = comparator.compare(key, node.getKey());
if (res < 0) {
node.setLeft(insertedNode);
}
else {
node.setRight(insertedNode);
}
treeFixUp(insertedNode);
this.length++;
}
}
#Override
public V get(K key) {
// TODO Auto-generated method stub
return null;
}
#Override
public void delete(K key) {
RBTreeWParentNode<K, V> node = root;
boolean oldColor;
int res;
while (node != null
&& (res = comparator.compare(key, node.getKey())) != 0) {
if (res < 0) node = node.getLeft();
else node = node.getRight();
}
if (node == null)
return;
oldColor = node.getColor();
// key found, work with children
if (!node.hasParent()) {//In root
root = null;
return;
}
else if(node.hasLeft() && !node.hasRight()) {//left child
node.getLeft().setParent(node.getParent());
node.getParent().setLeft(node.getLeft());
}
else if (!node.hasLeft() && node.hasRight()) {//right child
node.getRight().setParent(node.getParent());
node.getParent().setRight(node.getRight());
}
else if (node.hasLeft() && node.hasRight()) {//both children
RBTreeWParentNode<K, V> tmp = node;
node = min(tmp.getRight());
//fix parent node of node
node.setParent(tmp.getParent());
if (tmp.getParent().getLeft().equals(tmp)) {
node.getParent().setLeft(node);
}
else node.getParent().setRight(node);
node.setRight(deleteMin(tmp.getRight()));
node.setLeft(tmp.getLeft());
tmp = null;
}
else { // is a leaf
if (node.equals(node.getParent().getLeft()) ) {
node.getParent().setLeft(null);
}
else node.getParent().setRight(null);
}
if (oldColor == false) {
deleteFixUp(node);
}
}
private RBTreeWParentNode<K, V> deleteMin(
RBTreeWParentNode<K, V> node) {
if (node.getLeft() == null) {
return node.getRight();
}
node.setLeft(deleteMin(node.getLeft()));
return node;
}
private RBTreeWParentNode<K, V> min(RBTreeWParentNode<K, V> node) {
if (node.getLeft() == null) {
return node;
}
else return min(node.getLeft());
}
private void deleteFixUp(RBTreeWParentNode<K, V> node) {
while (!node.equals(this.root) && node.isBlack()) {
if (node.equals(node.getParent().getLeft())) {
if (node.getParent().hasRight()) {
RBTreeWParentNode<K, V> w = node.getParent().getRight();
if (w.isRed()) {
w.setBlack();
node.getParent().setRed();
rotateLeft(node.getParent());
w=node.getParent().getRight();
}
if (w.hasLeft() && w.hasRight() && w.getLeft().isBlack() && w.getRight().isBlack()) {
w.setRed();
node = node.getParent();
}
else {
if (w.hasRight() && w.getRight().isBlack()) {
w.getLeft().setBlack();
w.setRed();
rotateRight(w);
w = node.getParent().getRight();
}
w.setColor(node.getParent().getColor());
node.getParent().setBlack();
w.getRight().setBlack();
rotateLeft(node.getParent());
node = this.root;
}
}
}
else {
//Repeat up changing left with right
if (node.getParent().hasLeft()) {
RBTreeWParentNode<K, V> w = node.getParent().getLeft();
if (w.isRed()) {
w.setBlack();
node.getParent().setRed();
rotateRight(node.getParent());
w=node.getParent().getLeft();
}
if (w.hasLeft() && w.hasRight() && w.getLeft().isBlack() && w.getRight().isBlack()) {
w.setRed();
node = node.getParent();
}
else {
if (w.hasLeft() && w.getLeft().isBlack()) {
w.getRight().setBlack();
w.setRed();
rotateLeft(w);
w = node.getParent().getLeft();
}
w.setColor(node.getParent().getColor());
node.getParent().setBlack();
w.getLeft().setBlack();
rotateRight(node.getParent());
node = this.root;
}
}
}
}
node.setBlack();
}
#SuppressWarnings("unused")
#Override
public boolean equals(Object other) {
if (!(other instanceof RBTreeWParentDictionary)) {
return false;
}
if ((this == null && other != null) || (this != null && other == null)) {
return false;
}
if (this == null && other == null) {
return true;
}
else {
#SuppressWarnings("unchecked")
RBTreeWParentDictionary<K, V> oth = (RBTreeWParentDictionary<K, V>) other;
return equalsNodes(this.root, oth.root);
}
}
private boolean equalsNodes(RBTreeWParentNode<K, V> node1,
RBTreeWParentNode<K, V> node2) {
if ((node1 == null && node2 != null) || (node1 != null && node2 == null)) {
return false;
}
else if (node1 == null && node2 == null) {
return true;
}
else return node1.equals(node2)
&& equalsNodes(node1.getLeft(), node2.getLeft())
&& equalsNodes(node1.getRight(), node2.getRight());
}
}
RBTreeWParentNode.java (Here is the node of RedBlackTree)
package dictionary;
public class RBTreeWParentNode<K, V> {
private K key;
private V value;
private boolean color;
private RBTreeWParentNode<K, V> left, right, parent;
private static final boolean RED = true;
private static final boolean BLACK = false;
public RBTreeWParentNode(K key, V value, RBTreeWParentNode<K, V> left,
RBTreeWParentNode<K, V> right, RBTreeWParentNode<K, V> parent) {
this.key = key;
this.value = value;
this.color = RED;
this.left = left;
if (this.hasLeft())
this.getLeft().setParent(this);
this.right = right;
if (this.hasRight())
this.getRight().setParent(this);
this.parent = parent;
}
public RBTreeWParentNode(K key, V value) {
this.key = key;
this.value = value;
this.color = RED;
}
public RBTreeWParentNode() {
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public boolean getColor() {
return color;
}
public RBTreeWParentNode<K, V> getLeft() {
return left;
}
public RBTreeWParentNode<K, V> getRight() {
return right;
}
public RBTreeWParentNode<K, V> getParent() {
return parent;
}
public RBTreeWParentNode<K, V> getBrother() {
if (this.hasParent()) {
if (this.getParent().getLeft().equals(this)) {
return this.getParent().getRight();
}
else return this.getParent().getLeft();
}
else return null;
}
public boolean isRed() {
return this.color == RED;
}
public boolean isBlack() {
return this.color == BLACK;
}
public boolean hasLeft() {
return this.getLeft() != null;
}
public boolean hasRight() {
return this.getRight() != null;
}
public boolean hasParent() {
return this.getParent() != null;
}
public boolean hasBrother() {
if (this.hasParent()) {
if (this.getParent().getLeft().equals(this)) {
return this.getParent().getRight() != null;
}
else return this.getParent().getLeft() != null;
}
else return false;
}
public void setKey(K key) {
this.key = key;
}
public void setValue(V value) {
this.value = value;
}
public void setRed() {
this.color = RED;
}
public void setBlack() {
this.color = BLACK;
}
public void setParent(RBTreeWParentNode<K, V> node) {
this.parent = node;
}
public void setLeft(RBTreeWParentNode<K, V> node) {
this.left = node;
if (this.hasLeft())
this.left.setParent(this);
}
public void setRight(RBTreeWParentNode<K, V> node) {
this.right = node;
if (this.hasRight())
this.right.setParent(this);
}
public void setColor(boolean color) {
this.color = color;
}
#Override
public boolean equals(Object other) {
if (!(other instanceof RBTreeWParentNode)) {
return false;
}
if ((this == null && other != null) || (this != null && other == null)) {
return false;
}
#SuppressWarnings("unchecked")
RBTreeWParentNode<K, V> oth = (RBTreeWParentNode<K, V>) other;
return checkFieldsEquals(oth);
}
private boolean checkFieldsEquals(RBTreeWParentNode<K, V> oth) {
//Check keys
if ((this.getKey() == null && oth.getKey() != null)
|| (this.getKey() != null && oth.getKey() == null)) {
return false;
}
else {
if ((this.getKey() == null && oth.getKey() == null)
|| this.getKey().equals(oth.getKey())) {
if ((this.getValue() == null && oth.getValue() != null)
|| (this.getValue() != null && oth.getValue() == null)) {
return false;
}
else {
if ((this.getValue() == null && oth.getValue() == null)
|| (this.getValue().equals(oth.getValue()))) {
if (this.getColor() != oth.getColor()) {
return false;
}
else {
return (this.getKey() == null && oth.getKey() == null)
|| this.getKey().equals(oth.getKey());
}
}
else return false;
}
}
else {
return false;
}
}
}
}
RBTreeWParentDictionaryTest.java -> My test class
Update 09/07/2016
I've updated my code because i found out that I wasn't updating the node cursor to root after the fix-up and I wasn't calling the fix-up only when the deleted node is black.
Considering my test case testDeleteDoubles I've figured out that I'm choosing a wrong candidate to switch with the item to delete when it has a brother.
Seeing this simulator the candidate should be the max node on the left branch of the deleted item, but shouldn't it be the successor, so the min item on the right branch?
In delete(), you need to remember the child node of the deleted node because the red-black properties might be violated after the delete. Let's say we declare RBTreeWParentNode<K, V> childOfDeletedNode;
Then, for the case of left child you update childOfDeletedNode = node.getLeft();
For the case of right child you update childOfDeletedNode = node.getRight();
For both children, you need to add the following after calling min():
oldColor = node.getColor();
childOfDeletedNode = node.getLeft();
node.setColor(tmp.getColor());
For leaf, take any child childOfDeletedNode = node.getRight();
Then, you fix the color of the child node with deleteFixUp(childOfDeletedNode);
Now since childOfDeletedNode can be null, you need to handle that case in deleteFixUp by adding a check for node != null in the loop condition and adding an if-statement before setting the color to black in the last line.
Anyway, the simulator you refer to finds the maximum node of the left sub-tree. Your solution finds the minimum node of the right sub-tree. Both are correct, but will result in different results. You'll need fix your test case.
To illustrate, before the delete:
10(B)
/ \
8(R) 100(B)
/ \
5(B) 9(B)
/ \
2(R) 6(R)
After the delete of 8, you replace it 9, the minimum node of the right sub-tree. The color is changed to red.
10(B)
/ \
9(R) 100(B)
/
5(B)
/ \
2(R) 6(R)
I'm having a little bit of difficulty with my insert method for this homework assignment. I have most of it done, but for some reason whenever my program is supposed to insert a node as a right child on the left side of the tree it just inserts it as a left child.
I kind of do my comparison in a weird way (signs should be reversed for a lot of them, but it worked like that for some reason) so please bear with me if you have difficulty in reading it.
I know that this is a horrible way to implement a binary search tree, and I would never ever do it in the real world, but it's homework and thus -- I have no choice.
Any and all help is appreciated, as always. Thank you!
Edit: I know where the problem is now. It's within the searchFor() method. Instead of the node's rightful parent, it makes the parent the root of the tree (in this case the parent of the node is always "cup".)
now that that's out of the way, can anyone offer up a solution?
Edit2: Took some of the extra stuff out that I don't think is relevant to the problem. I'm pretty sure I've narrowed it down to the searchFor() method. Whenever I call to return the parent of the current node, it will return the root of the tree ("cup.") I think that's why I'm having my problems, since it inserts based on that.
Thanks for all the help so far, I really appreciate it.
public class BinarySearchTree //implements Comparator
{
private Comparator<Object> dataComparator;
private LinkedListWithTwoLinks tree;
public static void main (String[] args)
{
BinarySearchTree bst;
Object hold;
String[] words = {"cup", "shaker", "cord", "key", "addressbook", "date", "address", "cupcake",
"card", "tape", "page", "day", "key", "days", "dayt"};
bst = new BinarySearchTree(new AlphabeticComparator());
System.out.println("[1]: original tree");
for(int i=0; i<words.length; i++) if (!bst.insert(words[i])) { System.out.println(">>>>>>>>>>>>> " + words[i] + " is already in tree"); }
bst.inOrder();
}
public static class AlphabeticComparator implements Comparator <Object>
{
public int compare(Object x, Object y)
{
if ( x == y ) return 0;
if ( x == null) return -1;
if ( y == null) return 1;
return (x.toString().compareTo(y.toString()));
}
}
public static class LastCharacterComparator implements Comparator <Object>
{
public int compare(Object x, Object y)
{
String xs;
String ys;
if ( x == y ) return 0;
if ( x == null ) return -1;
if ( y == null) return 1;
xs = x.toString();
ys = y.toString();
if ( xs.length() == 0) return -1;
if ( ys.length() == 0) return 1;
return (xs.charAt(xs.length()-1) - ys.charAt(ys.length()-1));
}
}
public BinarySearchTree(Comparator<Object> y)
{
dataComparator = y;
this.tree = new LinkedListWithTwoLinks();
}
private int compare(BinarySearchTreeElementInterface s, Object data)
{
return this.dataComparator.compare(s, data);
}
public boolean insert(Object data)
{
boolean success;
BinarySearchTreeElementInterface current;
BinarySearchTreeElementInterface parent;
current = getRoot();
parent = null;
success = false;
if (current == null)
{
getTree().insert(data);
return true;
}
else
{
SearchResult insert;
insert = searchFor(data);
//if (data == "shaker") {System.out.println(insert.resultOfCompare); }
while (current != null)
{
if (insert.insertAsLeftChild())
{
//if (data == "card") {System.out.println("IN RIGHT");}
//System.out.println("IN LEFT");
parent = current;
current = current.getLeftChild();
}
else if (insert.insertAsRightChild())
{
//if (data == "card") {System.out.println("IN RIGHT");}
parent = current;
current = current.getRightChild();
}
}
if (insert.insertAsLeftChild())
{
//parent.setLeftChild(insert.getParentOfLocation()); //insert.getParentOfLocation()
//System.out.println(data);
getTree().insertUsingPrior(parent, data);
//System.out.println(insert.getParentOfLocation()+" bye left");
// System.out.println(insert.getLocation()+" hi");
success = true;
}
else if (insert.insertAsRightChild())
{
//parent.setRightChild(insert.getParentOfLocation());
//System.out.println(data);
getTree().insertUsingNext(parent, data);
//System.out.println(insert.getParentOfLocation()+" bye right");
// System.out.println(insert.getLocation());
success = true;
}
else {success = false;}
/*
figures out if it should be inserted as a left or right child
then call insert using prior/next
}*/
}
return success;
}
private SearchResult searchFor(Object data)
{
/*returns either to node containing the data or the parent of the node of which the data would be a child of*/
if (getTree() == null) {throw new ListEmptyException("Tree is empty!");}
BinarySearchTreeElementInterface currentLocation;
BinarySearchTreeElementInterface parent;
SearchResult destination;
parent = getRoot();
currentLocation = parent;
while (currentLocation != null)
{
if (currentLocation.getData() == data)
{
return new SearchResult(parent, currentLocation, compare(currentLocation, data));
}
if (compare(currentLocation, data) < 0)
{
//System.out.println("IN LEFT");
parent = currentLocation;
currentLocation = currentLocation.getLeftChild();
}
else if (compare(currentLocation, data) > 0)
{
//System.out.println("IN RIGHT");
parent = currentLocation;
currentLocation = currentLocation.getRightChild();
}
}
destination = new SearchResult(parent, currentLocation, compare(parent, data));
//System.out.println(destination.resultOfCompare);
return destination;
/*
* use nothing but BSTEIs
*/
}
public void inOrder()
{
inOrder(getRoot());
}
public void inOrder(BinarySearchTreeElementInterface BSTroot)
{
//System.out.println(BSTroot.getRightChild());
if (BSTroot != null)
{
inOrder(BSTroot.getLeftChild());
System.out.println(BSTroot.getData());
inOrder(BSTroot.getRightChild());
}
/*if (BSTroot.getLeftChild() != null)
{
}
System.out.println(BSTroot.getData());
if (BSTroot.getRightChild() != null)
{
inOrder(BSTroot.getRightChild());
//System.out.println(BSTroot.getData());
}
System.out.println(BSTroot.getData());*/
}
public int size()
{
return tree.size();
}
/*SEARCH RESULT CLASS-----------------------------------------------------------------------------------------*/
public class SearchResult
{
BinarySearchTreeElementInterface location;
BinarySearchTreeElementInterface parentOfLocation;
int resultOfCompare;
public SearchResult(BinarySearchTreeElementInterface parent, BinarySearchTreeElementInterface locate, int comp)
{
this.parentOfLocation = parent;
this.location = locate;
this.resultOfCompare = comp;
}
public BinarySearchTreeElementInterface getLocation()
{
return this.location;
}
public BinarySearchTreeElementInterface getParentOfLocation()
{
return this.parentOfLocation;
}
public boolean insertAsLeftChild()
{
if (resultOfCompare > 0) {return true;}
else {return false;}
}
public boolean insertAsRightChild()
{
if (resultOfCompare < 0) {return true;}
else {return false;}
}
public boolean locationIsLeftOfParent()
{
return this.location == parentOfLocation.getLeftChild();
}
public boolean locationisRightOfParent()
{
return this.location == parentOfLocation.getRightChild();
}
public boolean wasSearchSuccessful()
{
return this.parentOfLocation == this.location;
}
public void setLocation(BinarySearchTreeElementInterface newLocation)
{
this.location = newLocation;
}
public void setLocationOfParent(BinarySearchTreeElementInterface newParentLocation)
{
this.parentOfLocation = newParentLocation;
}
}
}
compare(x, y) method of BinarySearchTree is wrong.
It compares a node to a data with a comparator made to compare data against data. Change 'Object' to 'String' and it will not compile while your sample data are strings.
This should fix it:
private int compare(BinarySearchTreeElementInterface s, Object data)
{
return this.dataComparator.compare(s.getData(), data);
}
In your SearchResult class, do you have the way it determines a left or right insert swapped?
public boolean insertAsLeftChild()
{
if (resultOfCompare > 0) {return true;}
else {return false;}
}
If the compare is greater than 0, it should be interested as a right child, correct?