I am working on a programming assignment that requires us to write a path(root, value) method that returns a LinkedList of Direction Enums (left, right) that leads to the target node (value). We are not allowed to create any new fields to make this happen, which is why I've created a pathHelper() method. One of the tests I'm failing is supposed to return: left, right as the path but it's returning left, right, left, right. I'm not sure why it's counting the steps twice. Any suggestions would be appreciated!
NOTE: This is a Binary Tree, not a BST. We are supposed to use an exhaustive DFS approach.
public static <T> LinkedList<BinaryNode.Direction> path(BinaryNode<T> root, T value) {
if (root == null) {
return null;
} else if (root.payload == value) {
return new LinkedList<>();
}
LinkedList<BinaryNode.Direction> list = new LinkedList<>();
pathHelper(root, value, list);
return list;
}
public static <T> void pathHelper(BinaryNode<T> root, T value, LinkedList<BinaryNode.Direction> list) {
if (root.left != null) {
if (root.payload != value) {
list.add(BinaryNode.Direction.left);
}
pathHelper(root.left, value, list);
} if (root.right != null) {
if (root.payload != value) {
list.add(BinaryNode.Direction.right);
}
pathHelper(root.right, value, list);
}
}
Your code has quite a few errors in it so I'm surprised any test cases are passing. You seem to be storing directions as you search the tree rather than when you find the value.
I suspect you are overcomplicating the problem. If you return a boolean from your helper function based on whether the item is found then you can easily add the directions when you return from the recursion:
private boolean findPath(BinaryNode<T> node, T value, List<BinaryNode.Direction> directions) {
if (node == null) {
return false;
} else if (node.payload.equals(value)) {
return true;
} else if (findPath(node.left, value, directions)) {
directions.add(0, BinaryNode.Direction.LEFT);
return true;
} else if (findPath(node.right, value, directions)) {
directions.add(0, BinaryNode.Direction.RIGHT);
return true;
} else {
return false;
}
}
Note that this inserts the direction at the start of the list to ensure it's in the correct order. This also allows you to detect where the root has the value because it will return true but the path will be empty.
Related
I'm trying to find a specific node in a binary tree using Java. My method for finding the node returns the node that contains the data that was searched for.
My code looks like this:
public BinNode find(Comparable item) throws NullPointerException {
if (item == null) {
throw new NullPointerException("item is NULL");
} else if (root == null) {
throw new NullPointerException("tree is empty");
}
return find(root, item);
}
public static boolean found = false;
public BinNode find(BinNode k, Comparable item) throws NullPointerException {
if (k.getData().equals(item)) {
found = true;
return k;
}
if (!found && k.getChildLeft() != null) {
find(k.getChildLeft(), item);
}
if (!found && k.getChildRight() != null) {
find(k.getChildRight(), item);
}
return k;
}
Running the debugger I can see, that when I search for an item that exists in the tree, it will find the correct node and go to the first return statement after "found" is set to true.
However, then compiler doesn't return that Node to the method call, but goes on to the second return statement, returning the root. So no matter where the Node is located, the method will always return the root.
What am I doing wrong?
Your method never returns "not found" which is fundamentally wrong because most of the times an item is not in the data. And that is your main problem. You need to return null / an empty Optional in the bottom return statement. And then you need to properly handle that "not found" return value when traversing the tree downwards, namely where you call find for the left and right child.
Your logic has to always be:
has the current node the correct value
if yes return the current node
does the left node contain the value
if yes return the corresponding node from the left
does the right node contain the value
if yes return the corresponding node from the right
return "not found" (because the current node is not correct and neither the left nor the right contain the value)
You currently skip / have not implemented the two nested "if yes return the corresponding node from the left/right" code paths.
(and of course remove the found variable as noted in a comment)
public BinNode find(BinNode k, Comparable item) throws NullPointerException {
if (k.getData().equals(item)) {
return k;
}
if (k.getChildLeft() != null) {
BinNode node = find(k.getChildLeft(), item);
if (node != null) return node;
}
if (k.getChildRight() != null) {
BinNode node = find(k.getChildRight(), item);
if (node != null) return node;
}
return null;
}
You need to return the finds from the left and right calls.
Your code finds the node and returns the k, but the other finds make no returns so your code continues on with code after the conditional statements, which is to return the node k. However, this falls back through the return stack to the original call to the double argument find, which has root as the BinNode given, so that is what is returned.
Refer Luk2302 answer.
You forgot "return" for left and right calls for find() function.
if (!found && k.getChildLeft() != null) {
return find(k.getChildLeft(), item);
}
if (!found && k.getChildRight() != null) {
return find(k.getChildRight(), item);
}
I'm trying to write a recursive code to check if a binary search tree is valid using an in-order traversal but without using an array. In other words, using only a previous value. I'm trying to keep the previous value as a parameter, but the code is failing. I've trie debugging but not sure why the code is not working.
class Solution {
public boolean isValidBST(TreeNode root) {
return isValidBSTPrev(root, null);
}
public boolean isValidBSTPrev(TreeNode root, TreeNode prev) {
if(root == null) {
return true;
} else if(isValidBSTPrev(root.left, root)
&& (prev!=null && root.val > prev.val)
&& isValidBSTPrev(root.right, root)) {
return true;
} else {
return false;
}
}
}
i am writing code for lop detection in linked list using hashmap. why it goes in infinite loop?
boolean hasCycle(Node head) {
HashMap<Integer,Node> map = new HashMap<Integer,Node>();
//<Address,data>
if(head == null || head.next == null)
return false;
Node p = head;
while(p.next!=null)
{
if(map.containsValue(p.next))
{
return true;
}
else
{
map.put(p.data,p.next);
}
p = p.next;
}
return false;
}
Use the Node as key and the data field as value and then check whether the HashMap contains the key:
boolean hasCycle(Node head) {
HashMap<Node,Integer> map = new HashMap<Node,Integer>();
if(head == null || head.next == null)
return false;
Node p = head;
while(p.next!=null) {
if (map.containsKey(p.next)) {
return true;
} else {
map.put(p.next,p.data);
}
p = p.next;
}
return false;
}
And also follow the Java Code Conventions.
Your code calls
map.containsValue(p.next)
This method iterates through the whole map looking for an object that is equal to the passed argument. To do that, it calls your Node.equals() method. It is highly probable that this is where it's going into an infinite loop.
To solve it, you could just use a HashSet of the Node objects (as mentioned in the comments) and check that your equals() and hashCode() methods are correct. But there is also another way to check for cycles, which doesn't involve the use of any extra memory. You just use two iterators, one going at half the speed of the other. If there is a cycle, the faster iterator will lap the slower one.
Have you defined .equals() and .hashCode() on your Node class? if not, it defaults to ==, and if the HashMap makes a copy of your Node as it inserts or moves it in memory, and then your equivalence would fail, because == compares memory addresses.
assuming your node class is akin to
public class Node{
public int data;
public Node next;
}
you could define them as
#Override
public int hashCode(){
int nextData=next.data;
return data^nextData;
}
#Override
public boolean equals(Object other){
boolean equal=false;
if(other!=null&&other instanceof Node){
Node otherNode=(Node)other;
if(otherNode.data==data){
if(otherNode.next==null&&next==null){
equal=true;
}else if(otherNode.next!=null&&next!=null){
if(otherNode.next.data==next.data){
equal=true;
}
}
}
}
return equal;
}
I want to check if a binary search tree is degenerate or not (Is it a linked list or indeed a tree?) I've been trying for a while and have come up with nothing that works. I did come up with a nonrecursive solution which I thought was quite clever but the specifications state it has to be a recursive solution and I'm having translating it from non-recursive to recursive.
Here's my non-recursive solution (well not really because size and height are both implemented recursively. This method however is not).
public boolean isDegenerate(){
if(this.size() == this.getHeight()){
return true;
}
return false;
}
Well, if you want a "more recursive" solution, how about this?
public boolean isDegenerate() {
if (this.left != null) {
if (this.right != null) {
return false; // not degenerate, has two children
} else {
return this.left.isDegenerate();
}
} else {
if (this.right != null) {
return this.right.isDegenerate();
} else {
return true; // we arrived at the bottom without seeing any node with two children
}
}
}
trying to write a boolean method that tells if someone is a decendant of someone...but can't seem to do it. of course, the object is a descendant if it's a child...or the descendant of a child.
public boolean isDescendant(member x){
if (children.contains(x)){
return true;
}
else{
return false;
}
}
but where or how do i insert:
for (int i = 0; i < children.size(); i++){
isDescendant(children.get(i));
}
thanks!
I think what you want is below:
// Cleaned up version
public boolean isDescendant(member x){
// check for direct descendance
if (children.contains(x)){
return true;
}
// check for being descendant of the children
for (Child c: children){
if (children.get(i).isDescendant(x)) {
return true;
}
}
return false;
}
Walking trees is very slow downwards (from the root to the leaves). Consider this implementation for the is-ancestor check:
/**
* Checks whether the given node is an ancestor of this node.
*/
public boolean isDescendantOf(Node ancestor) {
Preconditions.checkNotNull(ancestor, "Ancestor");
if (equals(ancestor)) {
// every node is an ancestor to itself
return true;
} else if (parent == null) {
// not related
return false;
} else {
// recursive call
return parent.isDescendantOf(ancestor);
}
}
The other way is now a piece of cake.
public boolean isDescendant(Node descendant) {
return descendant.isDescendantOf(this);
}
No loops, no exponentional effort.
PS:
In my example i would suggest renaming isDescendant to isAncestorOf.
public boolean isDescendant(member currentRoot, member x){
//check the current level
if (currentRoot.children().contains(x)){
return true;
}
//leaf
if( currentRoot.children().isEmpty() ){ return false; }
//try all my children
boolean found = false;
for( Member child : currentRoot.children() ){
found = isDescendant( child, x );
if( found ) break;
}
return found;
}
You need to recurse over the current root, most likely.
Edit: If your data structure has parent pointers, use these instead of searching your descendants in the tree. If not, consider adding them. See the answer from whiskeysierra for a solution with parent pointers. Only if adding them is not possible, consider this answer.
The current answers all have two loops through children (one in children.contains(), one later).
This variant may be a bit more efficient (but it does not change the O-class), and is a bit shorter. (If children is a set with fast contains-check (like HashSet) and often the hierarchy is not so deep (so you don't need to recurse at all), the other answers are better.)
public boolean isDescendant(Member x) {
for(Member child : children) {
if(child.equals(x) || child.isDescendant(x))
return true;
}
return false;
}
If a node is considered a descendant of itself, you can write it like this:
public boolean isDescendant(Member x) {
if(equals(x))
return true;
for(Member child : children) {
if(child.isDescendant(x))
return true;
}
return false;
}