Java Generics: compareTo and “capture#-of ?” - java

I'm trying to write an implementation of a BinaryTree whose object can be of any type that implements Comparable. However, I realize that won't completely work. For example, A String and a Double wouldn't be able to be inserted into the same tree, even though they both implement Comparable.
So, I would like to know if it's possible to write the code such that the BinaryTree can be instantiated with any value whose type implements Comparable, but any ensuing elements added to the tree must all share the same supertype as the root's value.
Here's the code I have so far:
public class BinaryTree {
private Node root;
public BinaryTree() {
this.root = null;
}
public Node lookup(Comparable<Object> value) {
return lookup(this.root, value);
}
private Node lookup(Node node, Comparable<Object> value) {
Node match = null;
if (match != node) {
if (value == node.value) {
match = node;
} else if (value.compareTo(node.value) < 0) {
return lookup(node.left, value);
} else {
return lookup(node.right, value);
}
}
return match;
}
public Node lookupNonRecursively(Comparable<Object> value) {
return lookupNonRecursively(this.root, value);
}
private Node lookupNonRecursively(Node node, Comparable<Object> value) {
Node match = null;
if (match != node) {
if (value == node.value) {
match = node;
} else {
Node root = node;
boolean found = false;
while (!found && root != null) {
if (root.value.compareTo(value) < 0) {
if (root.left == null) {
root.left = match = new Node(value);
found = true;
} else {
root = root.left;
}
} else {
if (root.right == null) {
root.right = match = new Node(value);
found = true;
} else {
root = root.right;
}
}
}
}
}
return match;
}
public Node insert(Comparable<Object> value) {
return insert(this.root, value);
}
private Node insert(Node node, Comparable<Object> value) {
if (node == null) {
node = new Node(value);
} else {
if (node.value.compareTo(value) <= 0) {
insert(node.left, value);
} else {
insert(node.right, value);
}
}
return node;
}
public Node insertNonRecursively(Comparable<Object> value) {
return insertNonRecursively(this.root, value);
}
private Node insertNonRecursively(Node node, Comparable<Object> value) {
if (node == null) {
node = new Node(value);
} else {
Node root = node;
boolean inserted = false;
while (!inserted) {
if (node.value.compareTo(root.value) < 0) {
if (root.left == null) {
root.left = node = new Node(value);
inserted = true;
} else {
root = root.left;
}
} else {
if (root.right == null) {
root.right = node = new Node(value);
inserted = true;
} else {
root = root.right;
}
}
}
}
return node;
}
public static class Node {
private Node left;
private Node right;
private Comparable<Object> value;
public Node(Comparable<Object> value) {
this.left = null;
this.right = null;
this.value = value;
}
}
}
And as a test, this will throw the error, The method insert(Comparable<Object>) in the type BinaryTree is not applicable for the arguments (Integer), if I try to run code like the following:
BinaryTree tree = new BinaryTree();
tree.insert(new Integer(1));
You can see I've implemented some different BinaryTree methods for this class, but the same rules would need to apply: any value passed into lookup() or insert() would also need to share the root's supertype. I have a feeling this is where some variant of <T extends Comparable<? super T>> is going to come into play, but my mind is just not figuring this one out.
Any ideas for how I might accomplish this?
As noted by #jp-jee, here's my solution (also with logic and other bugs fixed from untested first attempt), which works beautifully:
public class BinaryTree<T extends Comparable<T>> {
private Node<T> root;
public BinaryTree() {
this.root = null;
}
public Node<T> lookup(T value) {
return lookup(this.root, value);
}
private Node<T> lookup(Node<T> node, T value) {
Node<T> match = null;
if (match != node) {
if (value.equals(node.value)) {
match = node;
} else if (value.compareTo(node.value) < 0) {
return lookup(node.left, value);
} else {
return lookup(node.right, value);
}
}
return match;
}
public Node<T> lookupNonRecursively(T value) {
return lookupNonRecursively(this.root, value);
}
private Node<T> lookupNonRecursively(Node<T> node, T value) {
Node<T> match = null;
if (match != node && value != null) {
if (value.equals(node.value)) {
match = node;
} else {
Node<T> searchRoot = node;
boolean found = false;
while (!found && searchRoot != null) {
if (value.equals(searchRoot.value)) {
match = searchRoot;
found = true;
} else if (value.compareTo(searchRoot.value) < 0) {
searchRoot = searchRoot.left;
} else {
searchRoot = searchRoot.right;
}
}
}
}
return match;
}
public void insert(T value) {
this.root = insert(this.root, value);
}
private Node<T> insert(Node<T> node, T value) {
if (node == null) {
node = new Node<T>(value);
} else {
if (value.compareTo(node.value) <= 0) {
node.left = insert(node.left, value);
} else {
node.right = insert(node.right, value);
}
}
return node;
}
public void insertNonRecursively(T value) {
this.root = insertNonRecursively(this.root, value);
}
private Node<T> insertNonRecursively(Node<T> node, T value) {
if (node == null) {
node = new Node<T>(value);
} else {
Node<T> runner = node;
boolean inserted = false;
while (!inserted) {
if (value.compareTo(runner.value) < 0) {
if (runner.left == null) {
runner.left = new Node<T>(value);
inserted = true;
} else {
runner = runner.left;
}
} else {
if (runner.right == null) {
runner.right = new Node<T>(value);
inserted = true;
} else {
runner = runner.right;
}
}
}
}
return node;
}
public static class Node<T extends Comparable<T>> {
private Node<T> left;
private Node<T> right;
private T value;
public Node(T value) {
this.left = null;
this.right = null;
this.value = value;
}
public Node<T> getLeft() {
return left;
}
public Node<T> getRight() {
return right;
}
public T getValue() {
return value;
}
}
}

Make your Binary Tree generic like
public class BinaryTree<T extends Comparable<T>>{
...
}
Whenever creating a BinaryTree instance, specify the containied type:
new BinaryTree<MyClass>();
Where MyClass must implement Comparable<MyClass>, i.e. be comparable to Objects of the same class.
Your methods would read as (example):
public Node lookup(T value) { ... }
The same applies for your Node class. Make it generic the same way.

Related

Problem with recursive method for BST rRemove(BSTNode<T> current, T data, BSTNode<T> dummy) when using pointer reinforcement technique

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!

How to populate the BST and also print it in Inorder way

I am trying this code to populate the BST and then print it in the InOrder traversal format. But the root node is not getting populated compiling wihtout any error and Output is : "root is empty", so how to correct this code so that my BST gets populated in the Node root.
I tried to make Node root as static I thought it might be the case that root node might not be accessible from each method but it is not working, tried to change the name of the Node but it is also not working.
import java.util.*;
import java.io.*;
import java.lang.*;
class Node{
int data; Node left; Node right;
public Node(int data) {
this.data = data;
left = null;
right = null;
}
}
public class insert_tree {
static Node root;
insert_tree() //constructor
{
root = null;
}
public void addNode(int value) { // public method is called by the object and this public method calls the private method in which the root is also passed.
root = add(root, value);
}
private Node add(Node node, int value) {
if(node == null) {
return node;
}
if(value < node.data) {
node.left = add(node.left, value);
}
else if(value > node.data) {
node.right = add(node.right, value);
}
else {
return node;
}
return node;
}
private void inOrder(Node node) {
// node = root;
if(node != null) {
inOrder(node.left);
System.out.print(node.data + " ");
inOrder(node.right);
}
else {
System.out.print("root is empty");
}
//return null;
}
public void inorder() {
inOrder(root);
}
private void printRoot(Node root) {
System.out.println(root.data);
}
public void print() {
printRoot(root);
}
public static void main(String args[]) {
insert_tree obj = new insert_tree();
obj.addNode(20);
obj.addNode(14);
obj.addNode(25);
obj.addNode(10);
obj.addNode(16);
obj.addNode(25);
obj.addNode(21);
obj.addNode(30);
//printing the tree
obj.inorder();
}
}
The output should be the inorder traversal of the tree.
public void addNode(int value) { // public method is called by the object and this public method calls the private method in which the root is also passed.
root = add(root, value);
}
private Node add(Node node, int value) {
if(node == null) {
node = new Node(value);
}
else if(value == node.data) {
node.data = value;
}
else if(value < node.data) {
node.left = add(node.left, value);
}
else {
node.right = add(node.right, value);
}
return node;
}

How do I reference a method to add to a binaryTree?

I am tasked with building a BinaryTree that represents Morse Code. It branches left with each dot and right with each dash.
I can not figure out, however, why my method to add a Node does not seem to want to work with a BinaryTree object. IntelliJ says that it "can not resolve method".
I am certain that the BinaryTree is not the issue, because I was given detailed instructions on how to write the class by my instructor. Rather, I suspect that I am perhaps referencing the wrong thing here. I have already verified that the parameters being entered isn't the issue.
public static MorseCodeTree<Character> readMorseCodeTree()
{
MorseCodeTree<Character> morse = new MorseCodeTree<Character>();
Node<Character> newNode = new Node<Character>(null);
morse.addNode(newNode, letter, position);
private Node<Character> addNode(Node<Character> currentNode, char data, String morseCode)
{
if (currentNode == null)
{
currentNode = new Node(null);
}
if (morseCode.charAt(0) == '*')
{
currentNode = addNode(currentNode.left, data, morseCode.substring(1));
}
else if (morseCode.charAt(0) == '-')
{
currentNode = addNode(currentNode.right, data, morseCode.substring(1));
}
else
{
currentNode.data = data;
}
return currentNode;
}
BinaryTree class:
import java.io.Serializable;
import java.util.Scanner;
public class BinaryTree implements Serializable{
//implement Node class
protected static class Node<E> implements Serializable
{
protected E data;
protected Node<E> left;
protected Node<E> right;
public Node (E data)
{
this.data = data;
this.left = null;
this.right = null;
}
public String toString()
{
return data.toString();
}
}
protected Node root;
public BinaryTree()
{
root = null;
}
protected BinaryTree(Node<E> root)
{
this.root = root;
}
public BinaryTree(E data, BinaryTree<E> leftTree, BinaryTree<E> rightTree)
{
root = new Node<E>(data);
if (leftTree != null)
{
root.left = leftTree.root;
}
else
{
root.left = null;
}
if (rightTree != null)
{
root.right = rightTree.root;
}
else
{
root.right = null;
}
}
public BinaryTree<E> getLeftSubtree()
{
if (root != null && root.left != null)
{
return new BinaryTree<E>(root.left);
}
else
{
return null;
}
}
public BinaryTree<E> getRightSubtree()
{
if (root != null && root.right != null)
{
return new BinaryTree<E>(root.right);
}
else
{
return null;
}
}
public boolean isLeaf()
{
return (root.left == null && root.right == null);
}
public String toString()
{
StringBuilder sb = new StringBuilder();
preOrderTraverse(root, 1, sb);
return sb.toString();
}
private void preOrderTraverse(Node<E> node, int depth, StringBuilder sb)
{
for (int i = 1; i < depth; i++)
{
sb.append(" ");
}
if (node == null)
{
sb.append("null\n");
}
else
{
sb.append(node.toString() + "\n");
preOrderTraverse(node.left, depth + 1, sb);
preOrderTraverse(node.right, depth + 1, sb);
}
}
public static BinaryTree<String> readBinaryTree(Scanner scan)
{
String data = scan.next();
if (data.equals("null"))
{
return null;
}
else
{
BinaryTree<String> leftTree = readBinaryTree(scan);
BinaryTree<String> rightTree = readBinaryTree(scan);
return new BinaryTree<String>(data, leftTree, rightTree);
}
}
}
You're declaring the addNode(...) method within readMorseCodeTree(), so it's not in the scope of the class. The latter method should look like this:
public static BinaryTree<Character> readMorseCodeTree()
{
BinaryTree morse = new MorseCodeTree();
Node<Character> newNode = new Node<Character>(null);
morse.addNode(newNode, letter, position);
}

Iterating and root find in a java tree structure

I am new in tree like structures.I have write this kind of a tree.
How to iterate over a tree ?
How to find all roots (i have a method for the main root but i want to find all roots which are inside the tree) in a tree ?
What is the correct way to use a tree structure in java - every time write your one class or using TreeMap ?
TreeNode
public class TreeNode<T> {
private T value;
private boolean hasParent;
private ArrayList<TreeNode<T>> children;
public TreeNode(T value) {
if (value == null) {
throw new IllegalArgumentException("Cannot insert null value!");
}
this.value = value;
this.children = new ArrayList<TreeNode<T>>();
}
public final T getValue() {
return this.value;
}
public final void setValue(T value) {
this.value = value;
}
public final int getChildrenCount() {
return this.children.size();
}
public final void addChild(TreeNode<T> child) {
if (child == null) {
throw new IllegalArgumentException("Cannot insert null value!");
}
if (child.hasParent) {
throw new IllegalArgumentException("The node already has a parent!");
}
child.hasParent = true;
this.children.add(child);
}
public final TreeNode<T> getChild(int index) {
return this.children.get(index);
}
Tree
public class Tree<T> {
TreeNode<T> root;
public Tree(T value) {
if (value == null) {
throw new IllegalArgumentException("Cannot insert null value!");
}
this.root = new TreeNode<T>(value);
}
public Tree(T value, Tree<T>... children) {
this(value);
for (Tree<T> child : children) {
this.root.addChild(child.root);
}
}
public final TreeNode<T> getRoot() {
return this.root;
}
Here i can use all inner roots and all nodes.
while (!stack.isEmpty()) {
TreeNode<Integer> currentNode = stack.pop();
for (int i = 0; i < currentNode.getChildrenCount(); i++) {
TreeNode<Integer> childNode = currentNode.getChild(i);
if (childNode == null) {
System.out.println("Not a root.");
} else {
System.out.println(childNode.getValue());
counter += childNode.getChildrenCount();
}
}
}

Root node is null after inserting new node into AVLTree [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
So in simpletons, I am creating my own AVLTree data structure. Now when i add a new node into my tree, it seems to add fine.
EDIT: It doesnt seem to take into account my duplicates (nor add them to the original node's list by key).
But when i print the rootNode to see if it exists it doesn't exist. I can't figure out what the problem is with my add method.
Here is my AVLTree class:
package cw.util;
import java.util.ArrayList;
import java.util.Comparator;
public class AVLTree<K, V>
{
public class Node {
private K key;
private ArrayList<V> valuesList;
private Node left, right;
private int height;
public Node(K key, ArrayList<V> valuesList) {
this.key = key;
this.valuesList = valuesList;
this.height = 0;
}
public Node(V value) {
}
public void addToNode(V value) {
valuesList.add(value);
}
public K getKey() {
return key;
}
public ArrayList<V> getValues() {
return valuesList;
}
public Node getLeftChild() {
return left;
}
public Node getRightChild() {
return right;
}
public int getHeight() {
return height;
}
public Node getChildNodeFromSide(String side) {
switch(side) {
default: return null;
case "left": return left;
case "right": return right;
}
}
}
private Node rootNode;
private Comparator<K> comparator;
//Unused
public AVLTree() {
}
public AVLTree(Comparator<K> comparator) {
this.comparator = comparator;
this.rootNode = null;
}
public V insert(K key, V value) {
Node n = insert(key, value, rootNode);
if(n != null) {
for(V v : n.getValues())
System.out.println(v.toString());
System.out.println();
return value;
} else {
return null;
}
}
public Node insert(K key, V value, Node node) {
ArrayList<V> values = new ArrayList<V>();
values.add(value);
if(node == null)
node = new Node(key, values);
else if(comparator.compare(key, node.key) < 0) {
node.left = insert(key, value, node.left);
if(height(node.left) - height(node.right) == 2) {
if(comparator.compare(key, node.left.key) < 0)
node = rotateWithLeftChild(node);
else
node = doubleRotateWithLeft(node);
}
} else if(comparator.compare(key, node.key) > 0) {
node.right = insert(key, value, node.right);
if(height(node.right) - height(node.left) == 2) {
if(comparator.compare(key, node.right.key) > 0)
node = rotateWithRightChild(node);
else
node = doubleRotateWithRight(node);
}
} else node.getValues().add(value);
node.height = Math.max(height(node.left), height(node.right)) + 1;
return node;
}
public Node search(K key) {
return search(key, rootNode);
}
public Node search(K key, Node node) {
boolean isFound = false;
while((node != null) && !isFound) {
K nodeKey = node.getKey();
if(comparator.compare(key, nodeKey) < 0)
node = node.getLeftChild();
else if(comparator.compare(key, nodeKey) > 0)
node = node.getRightChild();
else {
isFound = true;
}
node = search(key, node);
}
if(isFound) return node;
else return null;
}
//Custom Methods
public boolean isEmpty() {
return rootNode == null;
}
private int height(Node n) {
return n == null ? -1 : n.getHeight();
}
private Node rotateWithLeftChild(Node node2) {
Node node1 = node2.left;
node2.left = node1.right;
node1.right = node2;
node2.height = Math.max(height(node2.left), height(node2.right)) + 1;
node1.height = Math.max(height(node1.left), node2.getHeight()) + 1;
return node1;
}
private Node rotateWithRightChild(Node node1) {
Node node2 = node1.right;
node1.right = node2.left;
node2.left = node1;
node1.height = Math.max(height(node1.left), height(node1.right)) + 1;
node2.height = Math.max(height(node2.left), node1.getHeight()) + 1;
return node2;
}
private Node doubleRotateWithLeft(Node node) {
node.left = rotateWithRightChild(node.left);
return rotateWithLeftChild(node);
}
private Node doubleRotateWithRight(Node node) {
node.right = rotateWithLeftChild(node.right);
return rotateWithRightChild(node);
}
}
Here is how I test the class:
package cw.avl;
import cw.util.AVLTree;
public class AVLTest
{
public static void main(String[] args) {
AVLTree<String, Integer> tree = new AVLTree<String, Integer>(String.CASE_INSENSITIVE_ORDER);
for (int i=1; i <= 10;i++) {
String s = "S" + i;
int x = i;
tree.insert(s, x);
tree.insert(s, x);
}
}
}
Well, you don't seem to ever assign to rootNode, so it starts null and remains so. In fact, your methods create nodes and return them:
if(node == null)
node = new Node(key, values);
...
return node
But you don't use the returned node.
Edit: longer explanation:
When you call from the other function like this: Node n = insert(key, value, rootNode); you are basically saying: Node n = insert(key, value, null);. On the receiving end, here:
public Node insert(K key, V value, Node node) { ,
you are creating a new variable called node with initial value null. Then you replace that value when you do:
node = new Node(key, values);
That value is for the node variable in the insert(K,V,N) method, in no way is rootNode retroactively updated. You could just do so right there:
if(node == null) {
node = new Node(key, values);
rootNode = node;
}

Categories

Resources