I have (recursively) defined a class for implementing a binary tree (in Java):
class BinaryTree {
protected int key;
protected BinaryTree left, right;
// some methods...
}
from which I want to implement a binary search tree, like this:
class BinarySearchTree extends BinaryTree {
// ...
public BinarySearchTree search(int x) {
if (x == key)
return this;
if (x < key)
if (left != null)
return left.search(x); // (*)
else
if (right != null)
return right.search(x); // (*)
return null;
}
}
but of course the lines marked with // (*) won't compile beacause left and right are just BinaryTrees, without any search() method.
So I am wondering if theres is a way to define BinarySearchTree from the BinaryTree superclass but with left and right being actually BinarySearchTrees.
Or maybe there is a better way of implementing the relationship between binary trees and the search ones: should I define a separate Node class? should I use templates? should I avoid recursive definitions at all? ...
You can use recursive generics.
Define a recursive generic type variable, say, B:
class BinaryTree<B extends BinaryTree<B>> {
and make your fields of this type:
protected B left, right;
Then define:
class BinarySearchTree extends BinaryTree<BinarySearchTree> {
Now left and right are of type BinarySearchTree too, allowing you to call left.search and right.search.
I feel BinaryTreeNode should be created as an inner class ofBinaryTree.java. BinaryTreeNode can have int data, and two references of type BinaryTreeNode for left and right node
BinaryTree.java should have an reference of type BinaryTreeNode which will be the root of the tree.
Now BinarySearchTree extends BinaryTree looks good, you can include an method in it as below signature.
BinaryTreeNode `search( int k, BinaryTreeNode root)`
Now you can define the recursive method.
Please see Sample code with basic skeleton.
BinaryTreeNode.java
public class BinaryTreeNode {
private int data;
private BinaryTreeNode left, right;
public BinaryTreeNode(int data) {
this.setData(data);
}
public BinaryTreeNode getLeft() {
return left;
}
public void setLeft(BinaryTreeNode left) {
this.left = left;
}
public BinaryTreeNode getRight() {
return right;
}
public void setRight(BinaryTreeNode right) {
this.right = right;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
BinaryTree.java
public class BinaryTree {
protected BinaryTreeNode root;
// other basic methods needed for creating the Binary tree.
}
BinarySearchTree.java
public class BinarySearchTree extends BinaryTree {
public BinaryTreeNode search(int k) {
return search(k, root);
}
private BinaryTreeNode search(int k, BinaryTreeNode root) {
if (root.getData() == k) {
return root;
}
if (root.getData() < k) {
return search(k, root.getRight());
} else {
return search(k, root.getLeft());
}
}
// add other methods needed for creating the Binary search tree.
// also override the methods which needs to be modified for their behavior
// for binary search tree
}
Related
this is my first post here, but I need help trying to figure out why my child class will not let me override the parent method. I was tasked to create a generic Binary Search Tree with some functionality. The next task was to create a generic AVL Tree and I decided to extend it from my custom Binary Search Tree to reuse code and simply add the rotation required to make it functional. However when trying to overwrite the method, I keep getting a name clash error. And if I get rid of my Comparable interface extension in my AVLTree class and make my insert method generic, I get an argument mismatch error saying T cannot be converted to Comparable. This is where I am stuck at, if anyone can offer any type of input it would be much appreciated.
public class BinaryTree <T extends Comparable<T>>{
Node Root;
public BinaryTree(){
this.Root = null;
}
public boolean isEmpty(){
return this.Root == null;
}
public void insert(T data){
this.insert(data, this.Root);
}
protected void insert(T data, Node<T> n){
if(this.Root == null){
this.Root = new Node(data);
}
if(data.equals(n.getData())){
n.occurances++;
}
else if(data.compareTo(n.data) < 0){
if(n.left != null)
insert(data, n.left);
else
n.left = new Node(data);
}
else if(data.compareTo(n.data) > 0){
if(n.right != null)
insert(data, n.right);
else
n.right = new Node(data);
}
}
First attempt:
public class AVLTree <T extends Comparable<T>> extends BinaryTree{
private static final int ALLOWED_IMBALANCE = 1;
public void insert(T data){
this.insert(data, this.Root);
}
Second attempt:
public class AVLTree extends BinaryTree{
private static final int ALLOWED_IMBALANCE = 1;
public <T>void insert(T data){
this.insert(data, this.Root);
}
error for overwriting insert method
Try passing the type parameter of BinaryTree:
// vvv
public class AVLTree <T extends Comparable<T>> extends BinaryTree<T> {
private static final int ALLOWED_IMBALANCE = 1;
#Override
public void insert(T data){
this.insert(data, this.Root);
}
}
I'm writing this in java.
I've got a BinaryTree Class. It has functions that use the Node class.
I've written a subclass of Binary Tree (TraversalTree) and I've got a subclass of the Node class (OrderNode).
How do I get the TraversalTree functions that inherit from BinaryTree to use the subclass OrderNode??
public class BinaryTree {
public Node root; // starting node of the tree
public Node getRoot() {
return root;
}
}
public class Node {
private int value;
private Node left, right, parent;
//constructor
public Node(int value) {
this.value = value; // data value to be stored in node
left = null; // left child
right = null; // right child
parent = null; // parent node
}
}
So here is the subclass OrderNode
public class OrderNode extends Node {
public int preOrder,postOrder, inOrder;
public OrderNode(int value) {
super(value);
}
}
And then in this subclass of BinaryTree, TraversalTree. I want it to have the subclass OrderNode replace all the Node calls in the BinaryTree functions.
public class TraversalTree extends BinaryTree {
}
I've tried to search this a bunch but I'm hitting a wall. Perhaps I haven't been able to find the right search terms. But either way I can't seem to find any info on this.
You can use super to access the super variables and assign sub class object in super class reference variables.
class TraversalTree extends BinaryTree {
public TraversalTree(OtherNode otherNode){
super.node=otherNode;
}
public OtherNode getRoot(){
return (OtherNode)super.getRoot();
}
}
This should replace all node with otherNode.
I have the following code where type T extends Comparable, but I get a compile error when I try to do
root.node.compareTo(min).
Saying compareTo does not apply. It seems generic type scope does not apply to inner class?
public class Tree<T extends Comparable> {
public class Node<T>{
private T node;
private Node<T> left;
private Node<T> right;
public Node(T node, Node<T> left, Node<T> right) {
super();
this.node = node;
this.left = left;
this.right = right;
}
}
public boolean isBalanced(Node<T> root){
return isBalanced(root, Integer.MIN, Integer.MAX);
}
private boolean isBalanced(Node<T> root, T min, T max){
if(root == null){
return true;
}
if(root.node.compareTo(min) < 0 || root.node.compareTo(max) > 0){
return false;
}
return isBalanced(root.left, min, root.node) || isBalanced(root.right, root.node, max);
}
}
When you say public class Node<T>, you're shadowing the <T> from the outer class. You should either remove the <T> from the inner class declaration or, better, make the inner class a static nested class (since there's no inherent reason the node needs to know about the tree it's attached to).
(Note: Also use <T extends Comparable<T>>.)
How do you insert items into a binary tree in java so that they are in order? I want to use random values and sort them from smallest to largest then insert them into a binary tree in this order:
1
2 3
4 5 6 7
8 9
When you say 'in order' you need to clarify, do you mean in sorted order or do you mean insertion order, etc.
There are lots of resources available on inserting into binary trees or the difference between to types of binary trees, or how to print a binary tree diagram, that I suspect this is a duplicate.
What is different about your example? Having '1' as the root node means you must not have a rebalancing tree since both '2' and '3' are larger than the value for your root node. Your insert rule seems inconsistent since if '1' is the first node inserted then all other values will cascade to the right branch of the tree unless you use a different rule for the root then at the other levels which would be a pain to code.
Something like this?:
public class BinaryTree {
private List<Integer> list = new ArrayList<Integer>();
public class BinaryTreeNode {
private int p;
public BinaryTreeNode(int p) {
this.p = p;
}
private BinaryTreeNode getChild(int childP){
BinaryTreeNode result= null;
if (childP < list.size()){
result = new BinaryTreeNode(childP);
}
return result;
}
public BinaryTreeNode getLeft(){
return getChild(p*2+1);
}
public BinaryTreeNode getRight(){
return getChild(p*2+2);
}
public int getValue(){
return list.get(p);
}
}
public void add(int item){
list.add(item);
}
public BinaryTreeNode getRoot(){
BinaryTreeNode result = null;
if (!list.isEmpty()){
result = new BinaryTreeNode(0);
}
return result;
}
}
In Naftalin, Walder Java Collections and Generics I've faced with this implementation that I love best:
public interface TreeVisitor<E, R> {
public R visit(E leaf);
public R visit(E value, Tree<E> left, Tree<E> right);
}
public abstract class Tree<E> {
public abstract <R> R accept(TreeVisitor<E, R> visitor);
public static <E> Tree<E> leaf(final E leaf) {
return new Tree<E>() {
#Override
public <R> R accept(TreeVisitor<E, R> visitor) {
return visitor.visit(leaf);
}
};
}
public static <E> Tree<E> branch(final E value, final Tree<E> left, final Tree<E> right){
return new Tree<E>(){
#Override
public <R> R accept(TreeVisitor<E, R> visitor) {
return visitor.visit(value, left, right);
}
};
}
}
Now you can add any operation you want and create your tree as follows:
Tree<Integer> t = Tree.branch(1,
Tree.branch(2,
Tree.branch(4, Tree.leaf(8), Tree.leaf(9)), Tree.leaf(5)),
Tree.branch(3, Tree.leaf(6), Tree.leaf(7));
I found the answer that I needed from this one.
Create a Complete Binary Tree using Linked Lists w/o comparing node values
Some of the other things I was pointed to, either weren't quite what I wanted, or didn't work past like 8 or so values.
Q: In my implementation of a binary tree below, why does the compiler choke at
if (data.compareTo(this.data) <= 0),
producing
Error: incompatible types: java.lang.Comparable<T> cannot be converted to T?
Both data and this.data are of type Comparable<T> and should be able to use or be an argument to the compareTo() method...right? Well, clearly not. But I really don't understand why. Generics are still baffling me.
public class MyBinaryTreeNodeG<T>{
Comparable<T> data;
MyBinaryTreeNodeG<T> parent;
MyBinaryTreeNodeG<T> left;
MyBinaryTreeNodeG<T> right;
public MyBinaryTreeNodeG(Comparable<T> data){
this.data = data;
}
public MyBinaryTreeNodeG<T> addChild(Comparable<T> data){
if (data.compareTo(this.data) <= 0) { //this is the line on which the compiler chockes
//check if left tree node is null. If so, add. Otherwise, recurse.
} else {
//same for the right tree node
return null;
}
The following is a clip from a more standard implementation of a binary tree. This compiles fine. But I still fail to see why this is a "better" (according to compiler) implementation than mine above.
public class MyBinaryTreeNodeG<T extends Comparable<T>>{
T data;
MyBinaryTreeNodeG<T> parent;
MyBinaryTreeNodeG<T> left;
MyBinaryTreeNodeG<T> right;
public MyBinaryTreeNodeG(T data){
this.data = data;
}
public MyBinaryTreeNodeG<T> addChild(T data){
if (data.compareTo(this.data) <= 0) {
//left node stuff
} else {
//right node stuff
return null;
}
If something is Comparable<T>, it is comparable to a T, not comparable to a Comparable<T>. That's why the second snippet works.
Look at the javadoc of Comparable : compareTo(T) is provided by the Comparable interface. This method allows to compare a object instance of T class implementing this interface with another T instance. In your first example, you're comparing a Comparable<T> with a Comparable<T> (and not with T)
This should work :
public class MyBinaryTreeNodeG<T> {
Comparable<T> data;
// ...
public MyBinaryTreeNodeG<T> addChild(final T data) {
if (this.data.compareTo(data) <= 0) {
} else {
}
// ...
}
}