I'm trying to code a binary search tree using java and currently I run into the problem of not being able to retain my value of root after calling certain methods.
Right now I'm writing the add() and height() methods which look like this:
public boolean add(E x) {
BinaryNode<E> temp = null;
if (root == null) {
root = new BinaryNode<>(x);
temp = root;
return true;
} else {
BinaryNode<E> node = root;
if(root.equals(x)){
root = temp;
return false;
}
if (node.element.compareTo(x) < 0) {
if (node.left == null) {
node.left = new BinaryNode<E>(x);
return true;
}
root = node.left;
add(x);
}
if (node.element.compareTo(x) > 0) {
if (node.right == null) {
node.right = new BinaryNode<E>(x);
return true;
}
root = node.right;
add(x);
}
root = temp;
}
return false;
}
A node is described by the following class:
static class BinaryNode<E> {
E element;
BinaryNode<E> left;
BinaryNode<E> right;
private BinaryNode(E element) {
this.element = element;
}
}
Now, I have BinaryNode root; as an attribute in my BST class. The purpose of this attribute is that it allows me to have methods without input parameters by recursively altering the value of root (for educational purposes only, I will not cheat here and use input parameters even though it might be easier).
The add(E x) method seems to be working properly but the problem is that the method height() also alters the attribute root, so when I use add(E x) after calling height() it doesn't work since I've yet to figure out how to retain the value of root through the height() method.
height() currently looks like this:
public int height() {
if(root == null){
return 0;
} else {
int lefth = 0;
int righth = 0;
BinaryNode<E> node = root;
if(root.left != null){
root = root.left;
lefth = height();
}
if(root.right != null){
root = root.right;
righth = height();
}
root = node;
if(lefth > righth){
return lefth+1;
} else {
return righth+1;
}
}
}
I know for sure that this method is faulty since it recursively changes the value of root (which is intended) but it fails in "resetting" the value of root to the actual root of the whole tree, if you know what I mean.
Inside my main method I wrote a couple lines of code to test if the two methods work and I'm quite sure that the add(E x) method works but the height() certainly doesn't work correctly. The purpose of height() is of course to return the height of the tree.
My main method has this:
public static void main(String[] args) {
BinarySearchTree<Integer> tree = new BinarySearchTree<>();
int a = 10;
int b = 11;
int c = 9;
int d = 9;
int e = 5;
int f = 8;
System.out.println("Adding " + a + " " + tree.add(a) + " \tHeight: " + tree.height());
System.out.println("Adding " + b + " " + tree.add(b) + " \tHeight: " + tree.height());
System.out.println("Adding " + c + " " + tree.add(c) + " \tHeight: " + tree.height());
System.out.println("Adding " + d + " " + tree.add(d) + " \tHeight: " + tree.height());
System.out.println("Adding " + e + " " + tree.add(e) + " \tHeight: " + tree.height());
System.out.println("Adding " + f + " " + tree.add(f) + " \tHeight: " + tree.height());
}
And it outputs the following lines into to console:
Adding 10 true Height: 1
Adding 11 true Height: 2
Adding 9 true Height: 2
Adding 9 false Height: 0
Adding 5 true Height: 1
Adding 8 true Height: 2
So, as it seems, my add(E x) is functioning properly since I'm not allowed to add duplicates. However I really don't know how to code height() correctly.
Any help would be greatly appreciated!
I've not gone through the code in detail but it looks/sounds like you are mixing temporary/local variables and class ones.
You are modifying the root node when you call height and this actually changes the globally scored one.
What you should instead do is have a local variable within the method that stores the current root and uses that to search, rather than modifying the global one.
i.e.
public int height() {
Node searchNode = root;
if(searchNode == null){
Now you do all the processing using searchNode without corrupting the global record of the root node.
Related
Node parent;
private int size;
public void addNodes() {
if (size == 0) {
Node n = new Node(sc.nextInt());
parent = n;
root = n;
size++;
}
System.out.println("Does " + parent.data + " have a left node");
if (sc.nextBoolean()) {
Node n = new Node(sc.nextInt());
parent.left = n;
parent = n;
addNodes();
}
System.out.println("Does " + parent.data + " have a right node?");
if (sc.nextBoolean()) {
Node n = new Node(sc.nextInt());
parent.right = n;
parent = n;
addNodes();
}
}
I cannot understand why the parent reference variable value of all recursive calls changes as soon as parent = n is done.
If there is any doubt in question, just run the program. I have tried to create a binary tree and initialize it using recursion.
I am creating a program that inserts a character (number/letter) into a binary tree. So far, I'm able to produce an output but it's not what I expected. These are the problems I'm encountering:
The insert method is not able to print the correct height of the tree. I am not sure where I should insert my height++; statement to get the correct output.
The insert method is only able to add nodes to the right.
Expected Output: ht=3 [K=3 L=[K=1 R=[K=2]] R=[K=5 L=[K=4]]]
My Output: ht=4 [K=3 R=[K=1 R=[K=2 R=[K=5 R=[K=4]]]]
(all nodes are only added to the right 'R')
Here are my classes for reference:
Main Class
BST<Character> bst = new BST<>();
bst.insert('3');
bst.insert('1');
bst.insert('2');
bst.insert('5');
bst.insert('4');
System.out.println("ht=" + bst.height + " " + bst.toString());
BST Class - where the insert method is declared
public class BST<T> extends BT<T> {
// insert() method
public void insert(char k)
{
if (root == null) {
root = new BTNode(k);
return;
}
BTNode<T> n = root;
BTNode<T> p = null; // parent
while (n != null) {
p = n;
if (k < n.value) {
n = n.left;
} else {
n = n.right;
}
}
if (k < p.value) {
p.left = new BTNode(k);
} else {
p.right = new BTNode(k);
height++; // adds 1 to height when a new level is made
}
}
}
BTNode Class
public class BTNode<T> {
T info;
int value, level;
BTNode<T> left, right;
public BTNode(T el) {
this(el, null, null);
}
public BTNode(T el, BTNode<T> l, BTNode<T> r) {
info = el;
left = l;
right = r;
}
}
BT Class - where the toString method is declared
public class BT<T> {
BTNode<T> root = null;
int height = 0;
public BT() {
BTNode<T> node = new BTNode("");
}
// other methods
// toString()
public String toString() {
return toString(root);
}
public String toString(BTNode<T> n) {
String s = "";
if (n == null) {
return "";
}
if (n != null) {
s = "[K=" + n.info;
if (n.left != null) {
s = s + " L=" + toString(n.left) + "]";
}
if (n.right != null) {
s = s + " R=" + toString(n.right) + "]";
}
}
return s;
}
}
Hope you can help me out, thanks!
You have quite a few issues in your code. I'll list a few immediate items but you really will need to learn to use an interactive debugger and unit testing to resolve the sorts of issues you are seeing.
You refer to the value field in BTNode in your comparison but it is never set. You should really be referring to info (which is the actual data in the node).
But given info is a generic type you can't use standard comparison operators. Instead you'll need to define it as <T extends Comparable<T>> and then use n.info.compareTo(k) > 0.
The key passed into insert should also be of type T
Which means the other classes also need to ensure T extends Comparable.
Height is only incremented when nodes are added to the right which makes no sense.
Height needs to be increased only when a node is inserted further from the root than the current maximum. Something like the following:
int depth = 0;
while (n != null) {
depth++;
p = n;
...
}
depth++;
if (depth > height)
height = depth;
You should get used to making your fields private and accessing them through getters. In your case a compareValue method would likely make sense.
Calling this function once works well and prints out all the contents of the Linked List I created. However, if I call it more than once, then it only prints the value of the head(line 2) from the next time it's called. Why is this? I am new to programming so any help would be much appreciated! Is there a way for me to test to find out the cause of the error?
public void printLinkedList(Node head) {
System.out.println("test: " + head.next.data);
Node n = head;
System.out.println("value: " + n.data);
while(n.next !=null) {
System.out.println("value: " + n.next.data);
n.next = n.next.next;
//n = n.next;
}
}
Solution from from comments above:
public void printLinkedList(Node head) {
System.out.println("test: " + head.next.data);
Node n = head;
System.out.println("value: " + n.data);
while(n.next !=null) {
System.out.println("value: " + n.data);
//n.next = n.next.next;
n = n.next;
}
}
There's a practice problem that I've been working on that's been confusing me.
Define a function treeLevelOrder which satisfies the following claim:
If Q is a binary search tree of integers, then treeLevelOrder(Q) is the String representation of the contents of Q according to their level in the tree.
We get this tree as an example
9
/ \
5 16
/ \ / \
1 7 12 19
The value of the expression treeLevelOrder(Q) in this case would be
"[9,5,16,1,7,12,19]".
I've seen similar problems, but they don't follow the same format that I'm looking for, wanting to print by level order or as ordered tuples. Here's some sample code I've been working on:
private String treeLevelOrder(Node Q)
{
if (Q.left == null && Q.right == null)
return "[" + Q.datum + "]";
else if (Q.left == null && Q.right != null)
return "[" + Q.datum + ", "+Q.right.datum+"]" + treeLevelOrder(Q.right);
else if (Q.left !=null && Q.right == null)
return"[" + Q.datum + ", "+Q.left.datum+", *]"+ treeLevelOrder(T.left);
else
return "[" + Q.datum + ", "+Q.left.datum+", "+Q.right.datum+"]" +
treeLevelOrder(Q.left) + treeLevelOrder(Q.right);
}
Any assistance would be helpful.
EDIT: Okay, so I've been experimenting with the level order example at Geeks for Geeks, thank you curlyBraces, that would be closer to what I'm looking for, though I can't figure out to make it return a string. Here's the code they use:
/* function to print level order traversal of tree*/
void printLevelOrder()
{
int h = height(root);
int i;
for (i=1; i<=h; i++)
printGivenLevel(root, i);
}
/* Compute the "height" of a tree -- the number of
nodes along the longest path from the root node
down to the farthest leaf node.*/
int height(Node root)
{
if (root == null)
return 0;
else
{
/* compute height of each subtree */
int lheight = height(root.left);
int rheight = height(root.right);
/* use the larger one */
if (lheight > rheight)
return(lheight+1);
else return(rheight+1);
}
}
/* Print nodes at the given level */
void printGivenLevel (Node root ,int level)
{
if (root == null)
return;
if (level == 1)
System.out.print(root.data + ", ");
else if (level > 1)
{
printGivenLevel(root.left, level-1);
printGivenLevel(root.right, level-1);
}
}
Any ideas?
Here's an implementation using while loop and two queues to keep track of all the nodes:
public String treeLevelOrder(Node root) {
StringBuilder result = new StringBuilder("");
Queue<Node> current = new LinkedList<>();
Queue<Node> other = new LinkedList<>();
if(root != null)
current.add(root);
while(!current.isEmpty()) {
while(!current.isEmpty()) {
Node node = current.remove();
result.append(",");
result.append(node.datum);
// adding children to the other queue
if(node.left != null)
other.add(node.left);
if(node.right != null)
other.add(node.right);
}
// swapping the queues
Queue<Node> temp = current;
current = other;
other = temp;
}
// building final string
if(result.length() == 0)
result.append("[");
else
result.setCharAt(0,'[');
result.append("]");
return result.toString();
}
As a programming exercise I need to rewrite some existing methods and classes that make up a binary tree. (The method signatures and constructors have to stay the same). Somehow I don't really seem to understand what I have done here.
Does the toString method have to public because it overwrites the Object class's toString method? And how can I avoid the nulls from being returned?
Here is the code I have come to so far:
Tree Class
Node root = null;
void addNode(int val) {
Node newNode = new Node(val);
root = newNode.addNode(root, val);
}
Node Class
Node(int val) {
val = val;
left = null;
right = null;
}
Node addNode(Node focusNode, int newNodeVal) {
if (focusNode == null)
return this;
if (newNodeVal == focusNode.val)
return focusNode;
if (newNodeVal < focusNode.val)
focusNode.left = this.addNode(focusNode.left, newNodeVal);
else
focusNode.right = this.addNode(focusNode.right, newNodeVal);
return focusNode;
}
public String toString() {
return this.left + " " + this.val + " " + this.right;
}
Use a StringBuilder to store the String representation of the node and append the data of the children nodes only in the specific node is not null. Here's an example using infix navigation on the nodes:
public String toString() {
StringBuilder sb = new StringBuilder();
if (this.left != null) {
sb.append(this.left);
sb.append(' ');
}
sb.append(this.val);
if (this.right != null) {
sb.append(' ');
sb.append(this.right);
}
return sb.toString();
}
public String toString() {
if(this.left==null){
return this.val + this.right;
} else if (this.right==null){
return this.left + this.val;
} else if (this.left == null && this.right == null){
return "";
} else {
return this.left + " " + this.val + " " + this.right;
}
}
You assign your nodes to null to start, and your toString method assumes that they have been altered. Imagine a tree where you added 5, then 3. Then called toString on the tree. It will try to print the node, 5 is the value, left is 3, right is null. When you try to call
return this.left + " " + this.val + " " + this.right;
You are saying to print
3 5 NULL
You can initialize left and right with an empty Node object (with no val) and when you print it you will see null as the val of an empty Node:
Node(Integer val) {
this.val = val;
left = new Node(null);
right = new Node(null);
}
This only works if you make val an Integer.
There is also a bug in your code:
val = val will leave this.val untouched. You have to use this.val = val;
toString() is overridden not overwritten. It has to return a String and you can't really avoid nulls if your Node is a leaf.
What you can do is writing toString() in a way it can be meaningful to have a null as val like this:
public String toString() {
return "#{val = " + val + ", left = " + left + ", right = " + right + "}"
}
Please note that this will traverse your tree recursively so to print your tree you only have to call root.toString().