This is part of a binary tree class, here is the find function, given the key to find the node in the tree, if not found return null, however this part have been recognized as dead code, when I move the if(current==null) statement to the bottom of inside while loop, it works, why? is it the same?
public class Tree {
public Node root;
public Node find(int key) {
Node current = root;
while (current.key != key) {
if (current == null) { //dead code here, why?
return null;
}
if (key < current.key) {
current = current.leftChild;
} else if (key > current.key) {
current = current.rightChild;
}
}
return current;
}
}
public class Node {
public char label;
public boolean visited = false;
public int key;
public float data;
public Node leftChild;
public Node rightChild;
}
If current is null it will never reach to the null check as you are accessing current.key beforehand it will throw a nullPointerException
If you move the if(current==null) to bottom as you are assigning new value before it won't be a dead code. (as the current.leftChild and current.rightChild might be null)
Because
while (current.key != key) // <-- current.key would throw NPE if current was null.
On the statement before, you're dereferencing current.key. If current == null, you will have an NPE. If it is not null, then the if check is meaningless since it will never be reached.
What you probably intended to do was move the if check to before the loop instead:
public Node find(int key) {
if (root == null) {
return null;
}
Node current = root;
while (current.key != key) {
if (key < current.key) {
current = current.leftChild;
} else if (key > current.key) {
current = current.rightChild;
}
}
return current;
}
This would give you the intended behavior that you want.
while (current.key != key) {
if (current == null) { //dead code here, why?
return null;
}
in your while condition you are already making sure that current is not null (by using current.key!=key) , so there's no point in rechecking it in if(current==null). if current=null, then you will get a NullPointerException in your while() and you will not even reach the if condition.
If current.key has not already thrown a NullPointerException through the attempt to access the key member, current cannot possibly be null at the beginning of the while loop. When the test is moved to the bottom of the loop, current has been assigned a new value which the compiler recognizes as potentially null.
Related
I'm doing a BST project which is search a value in the BST and return if it was found. I used a test method to check the codes, and it work fine. Problem came from the return type I guessed.
public BSTNode contains(BSTNode root, String needle) {
BSTNode current = root;
while (current != null) {
if (current.getData().compareTo(needle) > 0)
current=current.getLeft();
else if (current.getData().compareTo(needle) < 0)
current=current.getRight();
else if (current.getData().compareTo(needle) == 0)
return current;
else current=null;
}
return current;
}
result:
BSTNode node = bst.contains(root, "delta");
Assertions.assertTrue(node instanceof BSTNode);
false;
BSTNode node = bst.contains(root, "delta");
Assertions.assertTrue(true);
true;
As my understanding, I believe the codes work fine and the value return was right. I just don't understand the "node instance of BSTNode" why it was false and how can I fix it?
Thank you in advanced
Your method, as written, can only ever return null. You only exit the while loop when current is null, and then you return current. null instanceof Anything is always false.
The line current=current; will also cause an infinite loop if the value is found.
Both of these can be addressed at once: you should return current when the comparison is 0.
As you already got the point where you were actually wrong, I am adding one more constraint, by modifying your existing code.
In case of BST, there would be 3 points:
current node is equal to key node
current node is greater than the key node
current node is lesser than the key node
Therefore you need iterate until unless you found the key you were looking for or you traversed all possible keys. In either case you need to stop your iteration.
public BSTNode contains(BSTNode root, String needle) {
BSTNode current = root;
/* the variable you will return at the end */
BSTNode result = null;
/* iterate the loop until current becomes null or result becomes not null */
while (current != null && result == null) {
/* when you found what you were looking for */
if (current.getData().compareTo(needle) == 0){
result = current;
}else if (current.getData().compareTo(needle) > 0){
current=current.getLeft();
}else{
current=current.getRight();
}
}
/* return the result at the end, it will be either null or the value you were looking */
return result;
}
I have to make a so called "Hit Balanced Tree". The difference is that as you can see, my node class has an instance variable called numberOfHits, which increments anytime you call contains method or findNode method. The point of this exercise is to have the nodes with highest hit count on the top, so the tree basically reconstructs itself (or rotates). Root has the highest hit count obviously.
I have a question regarding a method I have to make, that returns the node with highest hit count. I will later need it to make the tree rotate itself (I guess, at least that's the plan). Here is my node class. (All the getters of course)
public class HBTNode<T> {
private HBTNode<T> left;
private HBTNode<T> right;
private T element;
private int numberOfHits;
public HBTNode(T element){
this.left = null;
this.right = null;
this.element = element;
this.numberOfHits = 0;
}
What I have so far is this:
public int findMaxCount(HBTNode<T> node) {
int max = node.getNumberOfHits();
if (node.getLeft() != null) {
max = Math.max(max, findMaxCount(node.getLeft()));
}
if (node.getRight() != null) {
max = Math.max(max, findMaxCount(node.getRight()));
}
return max;
}
This works fine, except it returns an integer.I need to return the node itself. And since I have to do this recursively, I decided find the biggest hit count and then subsequently using this method in another method that returns a node, like this(it's probably really inefficient, so if you have tips on improvement, I am listening):
public int findMaxCount() {
return findMaxCount(root);
}
public HBTNode<T> findMaxCountNode(HBTNode<T> node) {
if (node.getNumberOfHits() == this.findMaxCount()) {
return node;
}
if (node.getLeft() != null ) {
return findMaxCountNode(node.getLeft());
}
if (node.getRight() != null) {
return findMaxCountNode(node.getRight());
}
return null;
}
I call the method like this:
public HBTNode<T> findMaxCountNode() {
return findMaxCountNode(root);
}
It returns null even though I think it should be fine, I am not that good at recursion so obviously I am missing something. I am open to any help, also new suggestions, if you have any about this exercise of mine. Thanks a lot.
Test code:
public static void main(String[] args) {
HBTree<Integer> tree = new HBTree<Integer>();
tree.add(50);
tree.add(25);
tree.add(74);
tree.add(19);
tree.add(8);
tree.add(6);
tree.add(57);
tree.add(108);
System.out.println(tree.contains(108)); //contains method increases the count by one
System.out.println(tree.contains(8));
System.out.println(tree.contains(8));
System.out.println(tree.contains(108));
System.out.println(tree.contains(8));
System.out.println(tree.contains(108));
System.out.println(tree.contains(108));
System.out.println(tree.contains(108));
System.out.println(tree.findMaxCountNode());
}
Current output: true
true
true
true
true
true
true
true
null
Expected output: true
true
true
true
true
true
true
true
Element: 108
Left child: 6 //this is just a toString, doesn't matter at this point
Right child: null
Number of hits: 5
Seems like your two functions should look like the following. What I'm assuming here is that these functions, which are defined inside the HBTNode class, are designed to find the highest hit-count node below itself:
public HBTNode<T> findMaxCountNode(HBTNode<T> node) {
return findMaxCountNode(node, node);
}
public HBTNode<T> findMaxCountNode(HBTNode<T> node, HBTNode<T> maxNode) {
HBTNode<T> currMax = (node.getNumberOfHits() > maxNode.getNumberOfHits()) ? node : maxNode;
if (node.getLeft() != null ) {
currMax = findMaxCountNode(node.getLeft(), currMax);
}
if (node.getRight() != null) {
currMax = findMaxCountNode(node.getRight(), currMax);
}
return currMax;
}
public int findMaxCount(HBTNode<T> node) {
HBTNode<T> maxNode = findMaxCountNode(node);
if (maxNode != NULL)
return maxNode.getNumberOfHits();
else
return -1;
}
Let me know if there are any issues, this is off the top of my head, but I thought it would be helpful to point out that the "integer" version of your method should just use the "Node finding" version of the method. The method you wrote to find the maximum value is quite similar to the one I wrote here to find the maximum node.
I asked my friends about this and they said you can never take the current to the previous node and when I asked why they didn't give me a clear reason can anyone help me?
//here is the signature of the method;
public void remove (){
Node<T> tmp = null;
tmp.next = head;
// I want to delete the current by the way!;
while (tmp.next != current)
tmp = tmp.next;
tmp.next = current.next;
//now am taking the current to the node before it so that it only becomes null if the linkedlist is empty;
current=tmp;
}
The basic idea is sound if you are looking to mutate an existing linked list and remove an element. Although there is a lack of curly braces after the while and a NullPointException that will occur at the first tmp.next.
Generally a remove method would be passed the data in the node to remove. It's unclear in your question what current is supposed to point to. Your code does not support removing the head of the list or empty lists (null head).
Here's a potential implementation:
public boolean remove(T value) {
if (head == null) {
return false;
} else if (head.value.equals(value)) {
head = head.next;
return true;
} else {
Node<T> current = head;
while (current.next != null) {
if (current.next.value.equals(value)) {
current.next = current.next.next;
return true;
}
current = current.next;
}
return false;
}
}
If the current variable is supposed to end up pointing to the node before the removed node then you have a problem: what happens if you are removing the head of the list?
I made a binary search tree in Java but I'm having troubles whit the deleting nodes part. I managed to erase the node when it has only 1 son, and I have the idea to make the deletion when it has 2 sons, anyways the method I'm using when it has no sons (when it's a leaf) is not working in Java. Normally in C++ I would assign the Node "null" but it doesn't work here.
if (numberOfSons(node) == 0) {
node= null;
return true;
}
That's the portion of the code that takes care of the nulling part. When I debug it, it is referencing the correct node and it's assigning it the null value, but when I return to the Frame where I'm calling the delete method for my tree the node is still there. What's the correct way to "null" an object in Java? I thought everything was a pointer in here and therefore this would work, but I think it doesn't.
When you're nulling something you just make the reference in the scope you're in null. It doesn't affect anything outside.
Let me explain by example. Say you have a method foo:
public void foo(Node node) {
node = null;
if(node == null) {
System.out.println("node is null");
} else {
System.out.println("node is not null");
}
}
Now you call it like this:
public void doSomething() {
Node node = new Node();
foo(node);
if(node == null) {
System.out.println("Original node is null");
} else {
System.out.println("Original node is not null");
}
}
In your console you'll get:
node is null
original node in not null
The reason is that it's not a pointer, it's a reference. When you're nulling a reference, you just say "make this reference synonym to null". It doesn't mean that the object is deleted, it may still exist in other places. There is no way to delete objects in java. All you can do is make sure no other object points to them, and the garbage collector will delete the objects (sometime).
Nothing remains but to reinsert either left or right subtree. For instance:
class BinaryTree<T extends Comparable<T>> {
class Node {
Node left;
Node right;
T value;
}
Node root;
void delete(T soughtValue) {
root = deleteRec(root, soughtValue);
}
Node deleteRec(Node node, T soughtValue) {
if (node == null) {
return null;
}
int comparison = soughtValue.compareTo(node.value);
if (comparison < 0) {
node.left = deleteRec(node.left, soughtValue);
} else if (comparison > 0) {
node.right = deleteRec(node.right, soughtValue);
} else {
if (node.left == null) {
return node.right;
} else if (node.right == null) {
return node.left;
} else {
// Two subtrees remain, do for instance:
// Return left, with its greatest element getting
// the right subtree.
Node leftsRightmost = node.left;
while (leftsRightmost.right != null) {
leftsRightmost = leftsRightmost.right;
}
leftsRightmost.right = node.right;
return node.left;
}
}
return node;
}
}
As Java does not have aliases parameters as in C++ Node*& - a kind of in-out parameter, I use the result of deleteRec here. In java any function argument that is an object variable will never change the variable with another object instance. That was one of the language design decisions like single inheritance.
I'm trying to implement an Iterator in my own TreeSet class.
However my attempt at creating it only works until the current node is the root.
The Iterator looks like this:
Constructor:
public TreeWordSetIterator()
{
next = root;
if(next == null)
return;
while(next.left != null)
next = next.left;
}
hasNext:
public boolean hasNext()
{
return next != null;
}
Next:
public TreeNode next()
{
if(!hasNext()) throw new NoSuchElementException();
TreeNode current = next;
next = findNext(next); // find next node
return current;
}
findNext:
private TreeNode findNext(TreeNode node)
{
if(node.right != null)
{
node = node.right;
while(node.left != null)
node = node.left;
return node;
}
else
{
if(node.parent == null)
return null;
while(node.parent != null && node.parent.left != node)
node = node.parent;
return node;
}
}
This works fine up until I get to my root node. So I can only iterate through the left child of root, not the right. Can anyone give me a few tips on what I'm doing wrong? I don't expect a solution, just a few tips.
Question: How can I find the next node in a TreeSet given each node points to its parent, left-child and right-child.
Thanks in advance
It helps to consider the rules of a Binary Search Tree. Let's suppose the previously returned node is n:
If n has a right subtree, then the node with the next value will be the leftmost node of the right subtree.
If n does not have a right subtree, then the node with the next value will be the first ancestor of n that contains n in its left subtree.
Your code is correctly handling the first case, but not the second. Consider the case where node is the leftmost leaf of the tree (the starting case). node has no right child, so we go straight to the else. node has a parent, so the if-clause is skipped. node.parent.left == node, so the while clause is skipped without executing at all. The end result is that node gets returned. I'd expect your iterator to continue returning the same node forever.
There are 3 main ways you can iterate a binarry tree
private void inOrder(TreeNode node) {
if(isEmpty())return;
if(node.getLeftNode()!=null)inOrder(node.getLeftNode());
System.out.print(node.getNodeData()+" ");
if(node.getRightNode()!=null)inOrder(node.getRightNode());
}
private void preOrder(TreeNode node) {
if(isEmpty())return;
System.out.print(node.getNodeData()+" ");
if(node.getLeftNode()!=null)preOrder(node.getLeftNode());
if(node.getRightNode()!=null)preOrder(node.getRightNode());
}
private void postOrder(TreeNode node) {
if(isEmpty())return;
if(node.getLeftNode()!=null)postOrder(node.getLeftNode());
if(node.getRightNode()!=null)postOrder(node.getRightNode());
System.out.print(node.getNodeData()+" ");
}
//use
inOrder(root);
preOrder(root);
postOrder(root);
Its simple as that ,your code doesn't really makes sense to me, is there something else you are trying to do besides iterating in one of this ways?
I think you need to save previous point in your iterator so you know where you've been before
Here some code but be aware that it is not complete you should do it by yourself and it's just to show you the idea. it also doesn't handle the root node.
findNext(TreeNode node, TreeNode previousNode) {
if(node.left != null && node.left != previousNode && node.right != previousNode){ //go left if not been there yet
return node.left;
}
if(node.right != null && node.right != previousNode){ //go right if not been there yet
return node.right;
}
return findNext(node.parent, node); //go up and pass current node to avoid going down
}
A good approach is to use a stack to manage sequencing, which is sort of done for you if you use a recursive traversal (instead of trying to build an Iterator at all) as described in SteveL's answer.
As you want to start from the left, you first load onto the stack the root node and its leftmost children in the proper order (push while going down to the left from the root).
Always pop the next from the top of the stack, and push its right child (if any) and all its leftmost children before returning the one you just popped, so that they're next in line.
By this approach, the top of the stack will always be the next to return, and when the stack is empty, there's no more...
In code:
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Stack;
public class TreeNodeInOrderIterator<T> implements Iterator<T> {
private final Stack<TreeNode<T>> stack;
public TreeNodeInOrderIterator(TreeNode<T> root) {
this.stack = new Stack<TreeNode<T>>();
pushLeftChildren(root);
}
#Override
public boolean hasNext() {
return !stack.isEmpty();
}
#Override
public T next() {
if (!hasNext())
throw new NoSuchElementException();
TreeNode<T> top = stack.pop();
pushLeftChildren(top.right);
return top.val;
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
private void pushLeftChildren(TreeNode<T> cur) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
}
}
In this code, TreeNode is defined by
public class TreeNode<T> {
T val;
TreeNode<T> left;
TreeNode<T> right;
TreeNode(T x) { val = x; }
}
If you want to have each node also know its parent, that's ok, but all the traversal is by using what's on the stack and adding to the stack using the left and right child links.