This is my implementation of BST in Java.
public class BST {
Node root;
public BST(){
root = null;
}
// public BST(int item){
// root = new Node(item);
// }
private class Node{
int data;
Node left;
Node right;
public Node(int data){
this.data = data;
this.left = null;
this.right = null;
}
}
public void add(int item){
add(item, root);
}
private Node add(int item, Node p ){
if(p == null){
p = new Node(item);
}
else if(item < p.data) p.left = add(item, p.left);
else if(item > p.data) p.right = add(item, p.right);
return p;
}
public void inorder(){
inorder(root);
}
private void inorder(Node p){
if(p == null) return;
inorder(p.left);
System.out.print(p.data + " ");
inorder(p.right);
}
}
This is the calling code.
public class Main {
public static void main(String[] args) {
// write your code here
//BST bst = new BST(13);
BST bst = new BST();
bst.add(12);
bst.add(7);
bst.add(3);
bst.add(2);
bst.add(19);
bst.add(4);
bst.add(17);
bst.add(11);
bst.inorder();
}
}
The issue here is when I use the BST parameterized constructor, everything works as expected. But if I dont and use the default constructor, the root continues to remain null and nothing gets added. Can't seem to understand why this is happening. The debugger gives a null pointer exception inside the add helper call. But the way my add is defined if a null root is the caller, then there should be no exceptions at all. My question is why is the BST with default constructor not working?
Correct add method like this:
public void add(int item)
{
root = add(item, root);
}
instead of this:
public void add(int item)
{
add(item, root);
}
In this method private Node add(int item, Node p ) you are returning p but then public void add(int item) doesn't store it. So basically whatever object you are returning, doesn't have a reference.
Change:
public void add(int item){
add(item, root);
}
to:
public void add(int item){
if (root == null)
root = add(item, root);
else
add(item, root);
}
Related
An abstract binary tree is to be created using a generic class. Each node has a string value as well as an initialCalculatedValue value. No changes should be made to the main class and a static inner class is to be included in the generic class. I'd like some advice on my code, as the main class is giving me error on accessing 'timesVisited' and 'values'. My code can't seem to access those variables.
Main class code:
public class Main{
public static void main(String[] args) {
WalkableTree<String, Integer> ast = new WalkableTree<>(0);
WalkableTree.Node<String, Integer> plus = ast.setRoot("+");
plus.setRightChild("20");
WalkableTree.Node<String, Integer> multiply = plus.setLeftChild("*");
multiply.setLeftChild("10");
WalkableTree.Node<String, Integer> bracketedPlus = multiply.setRightChild("+");
bracketedPlus.setLeftChild("3");
bracketedPlus.setRightChild("4");
// write visitor to display pre-order
System.out.println("Pre-order traversal:");
ast.walk(current -> {
if(current.timesVisited == 2)
System.out.print(current.value + " ");
});
System.out.println();
// write visitor to display in-order
System.out.println("In-order traversal:");
ast.walk(current -> {
if(current.timesVisited == 3)
System.out.print(current.value + " ");
});
System.out.println();
// write visitor to display post-order
System.out.println("Post-order traversal:");
ast.walk(current -> {
if(current.timesVisited == 4)
System.out.print(current.value + " ");
});
System.out.println();
}
}
Functional interface:
#FunctionalInterface
public interface Visitor<N> {
public void visit(N node);
}
Generic class:
public class WalkableTree <T, R> {
private T root = null;
private R initialCalculatedValue;
public static Node current;
public WalkableTree(R initialCalculatedValue) {
this.initialCalculatedValue = initialCalculatedValue;
}
public Node getRoot() {
return (Node) root;
}
public Node setRoot(T value) {
current = new Node(null,null,null,value,null,0);
return current;
}
public R getInitialCalculatedValue() {
return initialCalculatedValue;
}
public void setInitialCalculatedValue(R initialCalculatedValue) {
this.initialCalculatedValue = initialCalculatedValue;
}
protected void reset(Node node) {
node.timesVisited = 0;
node.calculatedValue = initialCalculatedValue;
reset((Node) node.leftChild);
reset((Node) node.rightChild);
}
public Node nextNode(Node node) {
node.timesVisited++;
if(node.timesVisited == 1)
return node;
if(node.timesVisited == 2)
return (Node) node.leftChild;
if(node.timesVisited == 3)
return (Node) node.rightChild;
if(node.timesVisited == 4)
return (Node) node.getParent();
return node;
}
public void walk(Visitor visitor) {
//Reset all the nodes in the tree
reset((Node) root);
//Set the current node to visit at the root of the tree
visitor.visit(root);
//Walking through the tree as long as the current node still exists
//If current node exists, let the visitor object visit the current node
//Current node is set to the next node using nextNode() method
while (this.current == current)
{
nextNode(current);
}
}
public static class Node<T, R> {
//Variables
Object leftChild;
Object rightChild;
Object parent;
T value;
R calculatedValue;
int timesVisited = 0;
public Node(Object leftChild, Object rightChild, Object parent, T value, R calculatedValue, int timesVisited) {
this.leftChild = leftChild;
this.rightChild = rightChild;
this.parent = parent;
this.value = value;
this.calculatedValue = calculatedValue;
this.timesVisited = timesVisited;
}
public Object getLeftChild() {
return leftChild;
}
public Node setLeftChild(T value) {
Node newLeft = new Node(null,null, current,value,0,0);
current = newLeft;
return current;
}
public Object getRightChild() {
return rightChild;
}
public Node setRightChild(T value) {
Node newRight = new Node(null,null, current,value,0,0);
current = newRight;
return current;
}
public Object getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public R getCalculatedValue() {
return calculatedValue;
}
public void setCalculatedValue(R calculatedValue) {
this.calculatedValue = calculatedValue;
}
public int getTimesVisited() {
return timesVisited;
}
public void setTimesVisited(int timesVisited) {
this.timesVisited = timesVisited;
}
}
}
Update the method in WalkableTree as below:
public void walk(Visitor<Node> visitor) {
//Reset all the nodes in the tree
reset((Node) root);
//Set the current node to visit at the root of the tree
visitor.visit((Node) root);
//Walking through the tree as long as the current node still exists
//If current node exists, let the visitor object visit the current node
//Current node is set to the next node using nextNode() method
while (this.current == current)
{
nextNode(current);
}
}
I have a BinaryTree class which contains an inner class Node.
What I would like to do is to be able to insert some nodes in my BinaryTree tree by calling tree.insert(node). However, to keep it clean and consistent, I dont want to create an insert() method inside Node inner class. So I tried the code below, but I have an error: Cannot cast from BinaryTree.Node to BinaryTree.
What should I do?
BinaryTree class
public class BinaryTree {
Node root = null;
private class Node {
int value;
Node left;
Node right;
}
public BinaryTree(int v) {
root.value = v;
root.left = null;
root.right = null;
}
public void insert(Node n) {
/* Error */
if(n.value > root.value) ((BinaryTree) root.right).insert(n);
}
}
Main class
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc = new Scanner(System.in);
String[] str = sc.nextLine().split(" ");
BinaryTree tree;
for(int i = 0; i < str.length-1; i++) {
int val = Integer.parseInt(str[i]);
//tree.insert(node);
}
}
}
Thanks,
You don't need typecasting inside insert method. It should be like this:
public void insert(Node n) {
if(n.value > root.value)
insert(root.right);
}
To insert a node in a tree you need to define where to insert it, so your insert methods should be something like:
//insert a new node right to a node. not null safe
public void insert(Node newNode, Node rightTo) {
newNode.right = rightTo.right;
newNode.left = rightTo;
rightTo.right = newNode;
}
which does not require casting.
To find the rightTo node you could use:
//get the last node which has a value lower than `value`
//may return null
public Node getNodeWithValueLowerThan(int value) {
if(root == null) return null;
return getNodeWithValueLowerThan(root, value);
}
//recursive method. null safe
private Node getNodeWithValueLowerThan(Node node, int value) {
if(node == null) return null;
if(node.value > value) return node.left; //return previous node. may be null
return getNodeWithValueLowerThan(node.right, value);
}
To insert a node as a last node, you could use:
//insert a new node as last
public void insertLastNode(Node newNode) {
Node lastNode = getTail();
if(lastNode == null) {//empty tree
root = newNode;
return;
}
newNode.left = lastNode;
lastNode.right = newNode;
}
where getTail is something like:
//find last node
private Node getTail() {
if(root == null) return null;
return getTail(root);
}
//recursive method to find last node. not null safe
private Node getTail(Node node) {
if(node.right == null) return node;
return getTail(node.right);
}
Note: code was not tested so debug carefully.
below is the code for BinaryTree.java insertion . Every time i insert a new node , the root is null.What i want , after 1st insert , root should not be null and it should remember the 1st insert and then for 2nd insert, the condition if (root ==null) should be false.
import java.util.LinkedList;
public class BinaryTree {
private BTNode root;
public int size;
public BinaryTree(){
this.root= null;
}
// public BTNode getRoot(){
// return this.root;
// }
public void insert(int data){
insert(data, root);
//calling insert function that takes data and root to insert
}
private void insert (int data, BTNode root){
//case 1: no element in binary tree
if (root == null){
// if root is null create a new BTNode and make it root
BTNode newN= new BTNode(data);
newN.setLeft(null);
newN.setRight(null);
root =newN;
//System.out.println(root.getData());
size++;
return;
//return root.getData();
}
//case2: tree not empty
//create a queue and traverse each node left-right
LinkedList<BTNode> q = new LinkedList<BTNode>();
q.addFirst(root);
while(!(q.isEmpty())){ //if queue not empty
BTNode temp= (BTNode) q.removeFirst();
//check left
if (temp.getLeft()==null){
//create a node and set left
BTNode newN= new BTNode(data);
newN.setLeft(null);
newN.setRight(null);
temp.setLeft(newN);
size++;
return;
//return root.getData();
}
else{
q.addLast(temp.getLeft());
}
//check right in case left is not null
if (temp.getRight()==null){
//create a node and set right
BTNode newN= new BTNode(data);
newN.setLeft(null);
newN.setRight(null);
temp.setRight(newN);
size++;
return;
//return root.getData();
}
else{
q.addLast(temp.getRight());
}
}//while loop ends here
return ;
}// insert(data,root) function ends here
}//class ends here
below is code for BTNode.java
public class BTNode {
int data;
private BTNode left=null;
private BTNode right=null;
public BTNode(){
}
public BTNode(int data){
this.data=data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public BTNode getLeft() {
return left;
}
public void setLeft(BTNode left) {
this.left = left;
}
public BTNode getRight() {
return right;
}
public void setRight(BTNode right) {
this.right = right;
}
}
TestMain.java
public class TestMain {
public static void main(String[] args){
BinaryTree btree = new BinaryTree();
btree.insert(1);
//System.out.println(btree.getRoot().getData());
btree.insert(2);
btree.insert(3);
btree.insert(4);
btree.insert(5);
btree.insert(6);
}
}
TestMain.Java
public class TestMain {
public static void main(String[] args){
BinaryTree btree = new BinaryTree();
btree.insert(1);
System.out.println(btree.getRoot().getData());
}
inside BinaryTree:
public BTNode getRoot(){
return this.root;
}
private void insert (int data, BTNode rootParameter){ // your problem is here
//case 1: no element in binary tree
if (root == null){
// if root is null create a new BTNode and make it root
BTNode newN= new BTNode(data);
newN.setLeft(null);
newN.setRight(null);
root =newN;
//System.out.println(root.getData());
size++;
return;
//return root.getData();
}
// other part of your code
}
the problem is that you are assigning your root to parameter but you should assign it to root variable outside of your method. you won't get null reference now.
I am trying to print a binary tree by BFS.
my implementation is with a PriorityQueue.
in the beginning i insert root into PriorityQueue.
then in loop, i pull a node from PriorityQueue, print it, and insert his childs(if thay are not null) into PriorityQueue.
why when inserting the second node, i get this exception:
Exception in thread "main" java.lang.ClassCastException: Node cannot be cast to java.lang.Comparable
this is my code:
class main:
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Tree tree = new Tree();
}
}
class Node:
public class Node {
public Node(){}
public Node(int num)
{
value = num;
}
private int value;
private Node left;
private Node right;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
}
class tree:
public class Tree {
private Node root;
public Tree()
{
root = new Node(5);
Node node2 = new Node(2);
Node node10 = new Node(10);
Node node8 = new Node(8);
Node node6 = new Node(6);
Node node15 = new Node(15);
root.setRight(node10);
root.setLeft(node2);
node10.setRight(node15);
node10.setLeft(node8);
node8.setLeft(node6);
printToWidth(root);
}
public void printToWidth(Node node)
{
PriorityQueue<Node> queue = new PriorityQueue<Node>();
queue.add(node);
while( !(queue.isEmpty()))
{
Node n = queue.poll();
System.out.println(n.getValue());
if (n.getLeft() != null)
queue.add(n.getLeft());
if (n.getRight() != null)
queue.add(n.getRight());
}
System.out.println("end printToWidth");
}
}
You've got two options:
Make Node implement Comparable<Node>, so that the elements can be inserted according to their natural ordering. This is likely the easier of the two.
public int compareTo(Node other) {
return value - other.getValue();
}
Use a custom Comparator<Node> and supply a compare method there, with an initial capacity.
PriorityQueue<Node> queue = new PriorityQueue<Node>(10, new Comparator<Node>() {
public int compare(Node left, Node right) {
return left.getValue() - other.getValue();
}
});
The exception is telling you, make Node implement Comparable<Node>.
You can insert the first node because it has nothing to compare to, so the comparison is not needed.
Im new to generics and i have to implement a binary search tree using generics. I did that but now im wondering how do i test the code that i wrote? Do i just make another class and start using the methods of the bst?
any help would be appreciated. below is my code just to clarify.
public class BST<E extends Comparable<E>>
{
public Node<E> root;
public BST()
{
root = null;
}
//insert delete find height
public void find(E s, Node<E> n)
{
//empty tree, root is null
if(n == null)
{
System.out.println("Item not present.");
}
//n is the node where s is, return n
else if(n.getData().equals(s))
{
System.out.println("Item present");
}
//s is greater than n, look for s on the right subtree
else if(s.compareTo(n.getData()) > 0)
{
find(s, n.getRight());
}
//s is less than n, look for s on the left subtree
else
{
find(s, n.getLeft());
}
}
public int height()
{
int count;
return count = height(root);
}
private int height(Node<E> n)
{
int ct = 0;
if(n == null)
{
}
else
{
int left = height(n.getLeft());
int right = height(n.getRight());
ct = Math.max(left, right) + 1;
}
return ct;
}
public void insert(E s)
{
root = insert(s, root);
}
private Node<E> insert(E s, Node<E> T)
{
//easiest case, empty tree, create new tree
if(T == null)
{
T = new Node<E>(s,null,null);
}
//easiest case, found s
else if(s.compareTo(T.getData()) == 0)
{
System.out.println("Item already present.");
}
//s is greater than T, insert on right subtree
else if(s.compareTo(T.getData()) > 0)
{
T.setRight(insert(s, T.getRight()));
}
//s is less than T, insert on left subtree
else
{
T.setLeft(insert(s,T.getLeft()));
}
return T;
}
public void delete(E d)
{
}
}
and my node class
public class Node<E>
{
private E data;
private Node<E> left;
private Node<E> right;
private Node<E> parent;
public Node(E d, Node<E> r, Node<E> l)
{
data = d;
left = l;
right = r;
}
public void setData(E d)
{
data = d;
}
public E getData()
{
return data;
}
public Node<E> getRight()
{
return right;
}
public void setRight(Node<E> nd)
{
right = nd;
}
public Node<E> getLeft()
{
return left;
}
public void setLeft(Node<E> nd)
{
left = nd;
}
public Node<E> getParent()
{
return parent;
}
public void setParent(Node<E> nd)
{
parent = nd;
}
}
Im trying to follow what you said, this is my test class
public class BSTTest
{
public void testInsert()
{
int height;
BST myTree = new BST();
myTree.insert(1);
}
}
but when i compile i get the error of unexpected type, it says if found an int but requires a reference on the line of BST myTree = new BST(); what does that mean?
Yes, make a class called BSTTest and create methods to test each of the public methods in BST.
If you use JUnit, you can use annotations and a standard naming convention
public class BSTTest {
#Test
public void testInsert() {
BST<String> bst = new BST<String>();
String s = "hello";
bst.insert(s);
AssertTrue("I should get back what I put in!", bst.find(s));
}
#Test
public void testDelete() {
// etc...
}
}
Then, you can run this 'Unit Test' in your java IDE (such as IntelliJ IDEA) or, if you have it set up, via maven: mvn test.
Also, I think your find() method could return boolean?
good luck!