Please find below my implementation for DFS.
protected void DFS(String search) {
for(Tree<T> child : leafs) {
if(child.value.equals(search))
return;
else
child.DFS(search);
System.out.println(child.value);
}
}
The objective is to stop traversal on finding the node whose value is in the variable search. However, the above function goes on traversing the tree even beyond the declared search node. Could someone help me modify the above function?
Thank you.
Edit 1
protected boolean DFS(String anaphorKey) {
boolean found = false;
for(Tree<T> child : leafs) {
if(child.head.equals(anaphorKey))
return true;
found = child.DFS(anaphorKey);
if(found == true)
break;
System.out.println(child.head);
//System.out.println("anaphorKey: "+anaphorKey);
}
return found;
}
Tried implementing the given answer suggestion (#SJuan76). The implementation above isn't working as desired. Could you point me to the place where code is not as per the logic suggested?
rookie, might I suggest an implementation using the classic for-loop (as opposed to the enhanced for-loop being used now) which allows integration of your stop-condition a bit better, something like:
protected boolean DFS(String key) {
boolean found = false;
for(int i = 0; i < leafs.size() && !found; i++) {
Tree<T> child = leafs.get(i);
if(child.head.equals(key))
found = true;
else
found = child.DFS(key);
}
return found;
}
So as soon as your found condition is hit, the 'found' becomes true and your loop stops.
What you may have forgotten is the "found = child.DFS(key)" portion of the recursion, where you need to remember the result of your recursive calls so ALL your for-loops on up the chain all break as soon as you return.
Hope that helps.
Option A (Nice): the function returns a value, when the node is found it returns a different value that if the node was not found. When you call to method, if you get the found value you stop the loop and return the found value too.
Option B (Ugly): When found, thow an Exception (better if it is your own implementation of it). Don't forget to catch it.
Option C (Uglier): The same with global (static) variables.
UPDATE 1:
It looks like your method should run ok now, can you check (System.out.println) if your value is ever found?
In a more personal opinion, I would find
protected boolean DFS(String anaphorKey) {
for(Tree<T> child : leafs) {
if(child.head.equals(anaphorKey))
return true;
if(child.DFS(anaphorKey)) // No need to store value. No need to check == true (it is implicit)
return true; // If we are in this line the value was found, always return true
System.out.println(child.head);
//System.out.println("anaphorKey: "+anaphorKey);
}
return false; // If the method did not exit previously it was because the value was not found, so in this line always return false
}
more readable (but it should work exactly as your implementation)
Related
Could someone tell me what's missing in my code. I am trying to remove the first occurrence of a given node value.
It fails very few test cases, but I am not sure what I am missing. Here is my code :
public boolean remove(E obj) {
if (obj == null)
throw new IllegalArgumentException("Violation of precondition : remove(E obj)");
DoubleListNode<E> current = head;
for (int i = 0; i < size; i ++) {
if (current.getData().equals(obj)) {
E result = remove(i);
return true;
}
current = current.getNext();
}
size --;
return false;
}
That recursive call to remove() inside the if block looks wrong.
You are already inside the list, you identified the first matching object. So now your code has to really remove that matching object. Removing would mean to update both links accordingly.
Do these things on paper! Draw a double linked list with nodes and the links between them. Then ask yourself what removing a node that has one or two links coming in (and potentially going out) actually means. You will have to change the links from the previous node and the one following the node that is to removed!
Im having troubles with a Graph assignment, i've run into an issue i cant seem to find.
System.out.println(plattegrond.getGraph().neighbours("Een").toString());
System.out.println(plattegrond.isRoute("Een", "Drie", new HashSet<String>()));
These lines of code print
[Twee, Drie, Vier]
false
So it seems, that "Een" has "Twee", "Drie", and "Vier" as neighbours.
However the isRoute method returns false. the method is shown below.
public boolean isRoute(String nodeA, String nodeB, Set<String> visited) {
visited.add(nodeA);
if(nodeA.equals(nodeB)) {
return true;
}
for(String neighbour : graph.neighbours(nodeA)) {
if(!visited.contains(neighbour)) {
return isRoute(neighbour, nodeB, visited);
}
}
return false;
}
I've traced all steps with the debugger, and in the enhanced for loop, "Drie" will not come up as a neighbour. "Twee" and "Four" however will. The same problem happens if i try to find a path to "Zes". When i ask "Twee" what its neighbours are, it will say
[Een, Vier, Zes]
the isRoute method will again return false when i ask it to find a route to "Zes". Again
"Zes" does not come up in the loop as neighbour.
However, when i ask it to find a route to either "Twee" or "Four" it will return true.
Im completely lost on this one.
There is a problem there... In your for you have IF statement with a return.. First Neighbour is Twee and it is not in the list so it will visit Twee and never go back to the next iteration because of that return statement.
Try using a boolean variable and doing something like this:
boolean b = false;
for(String neighbour : graph.neighbours(nodeA)) {
if(!visited.contains(neighbour)) {
// this statement can never change b to false once it becomes true
// and you make sure you return after checking your whole set of neighbours
b = b || isRoute(neighbour, nodeB, visited);
}
}
return b;
This might not be the exact correct solution but at least now you know where is your problem... You are returning after first item and not iterating over all the neighbours.
I get an error in the code from this part of my code:
public boolean findCustomer(String inPersonalNumber){
// check if personal number already exist
for (int i=0; i<customerList.size();i++) {
if(customerList.get(i).getCustomerPersonalNumber().equals(inPersonalNumber)){
return true;
}
}
return true;
}
When I remove the first return true and instead to the last return true, it don't get the error in my eclipse code, but why can't I have the first place and would this be the same? Thanks!
EDIT: The error message from eclipse say: This method must return a result of type boolean. I'm confused because isn't that what I have done?!
Yes, a break must be in the code
Can I write the method in some other way?
EDIT NUMBER 2
Why isn't this code working?
public boolean findCustomer(String inPersonalNumber){
// check if personal number already exist
for (int i=0; i<customerList.size();i++) {
if(customerList.get(i).getCustomerPersonalNumber().equals(inPersonalNumber)){
return true;
}
else {
return false;
}
}
}
This method returns a boolean value so I don't understand why I get an error!? The code looks right to me?
Your edit #2 doesn't compile because there is a possibility that your code won't enter the for-loop. This will be the case if customerList.size() is 0. To fix this, you'll simply need to add a return statement after the for-loop as well:
// check if personal number already exist
for (int i=0; i<customerList.size();i++) {
if(customerList.get(i).getCustomerPersonalNumber().equals(inPersonalNumber)){
return true;
}
else {
return false;
}
}
return false;
Another point here is that this code doesn't logically make much sense: it will only return true or false based on the first item in your list. And this is probably not what you want. So take a closer look at several of the other answer here, many of which are good examples for how you can do this.
public boolean findCustomer(String inPersonalNumber){
boolean result = false;
// check if personal number already exist
for (int i=0; i<customerList.size();i++) {
if(customerList.get(i).getCustomerPersonalNumber().equals(inPersonalNumber)){
result = true;
break;
}
}
return result ;
}
When I remove the first return true and instead to the last return
true, it don't get the error in my eclipse code, but why can't I have
the first place and would this be the same?
If you remove the second return statement the code would be able to run and not return a value - this is not possible as you defined the method to have a return type of Boolean. So it must always return a value no matter what.
Just change the second return statement to false, should do what you want.
Looks like you have turned off the Build Automatically feature of eclipse. It maybe complaining about an error that used to be present when you still hadn't typed in your code fully! This can also happen if you have back-dated your system for some reason.
Also, shouldn't you be returning false if the condition doesn't satisfy?
public boolean findCustomer(String inPersonalNumber) {
// check if personal number already exist
for (int i = 0; i < customerList.size(); i++) {
if (customerList.get(i).getCustomerPersonalNumber().equals(inPersonalNumber)) {
return true;
}
}
return false;
}
First return will return only in case of all conditions satisfied, but this method should be returning boolean as per code. It would be expecting a return in failure case also.
Removing first return won't affect compilation as it has a return in second place which will work without any condtions.
Edit : Answer for your second question
This code has two return's, but what if your customerList is size 0, in that case also, method must return boolean. right? for that only, compiler is asking.
BTW, code doesn't have null checks.
Your final code could be this. Keeping multiple return statements in code in not a good practice.
public boolean findCustomer(String inPersonalNumber) {
boolean retVal = false;
if (!(inPersonalNumber == null || inPersonalNumber.trim().equals("")
|| customerList == null || customerList.size() == 0)) { // inputs are valid to run this check
// check if personal number already exist
for (int i = 0; i < customerList.size(); i++) {
if (inPersonalNumber.equals(customerList.get(i).getCustomerPersonalNumber()) { // to avoid NPE, kept inPersonalNumber in check
retVal = true;
break;
}
}
}
return retVal;
}
Because your for loop looses meaning if you're returning true anyway.
If you want to stop loop use break; instead of first return.
In my program below, I set the variable th as true in the second if statement.
I'm curious why it later returns as false.
public boolean nodeExist(TreeNode Tree, T value){
boolean th = false;
if(Tree.getValue()!= null){
if(value == Tree.getValue()){
th = true;
}else{
if(value.compareTo((T) Tree.getValue()) < 0){
nodeExist(Tree.getLeft(), value);
}else{
nodeExist(Tree.getRight(), value);
}
}
}else{
th = false;
}
return th;
}
You probably look at a recursive call which sets th to true. But when that call returns to its caller, that th is still at false, and that's then returned. You need to assign the recursive callee's result:
if(value.compareTo((T) Tree.getValue()) < 0){
th = nodeExist(Tree.getLeft(), value);
}else{
th = nodeExist(Tree.getRight(), value);
}
You already got your answer. In future, to prevent mistakes like this, it's better to just return the value right away if you can. IT'S OKAY to have multiple return; if used properly, it can read to more readable code.
public boolean nodeExist(TreeNode Tree, T value){
if (Tree.getValue() == null) return false;
if (value == Tree.getValue()) return true;
if (value.compareTo((T) Tree.getValue()) < 0) {
return nodeExist(Tree.getLeft(), value);
} else {
return nodeExist(Tree.getRight(), value);
}
}
See also
Should a function have only one return statement?
Additionally, I noticed that you used == instead of equals for object comparison (i.e. T can't be a primitive type). This is rarely correct; equals is almost always what is really intended.
See also
Difference Between Equals and ==
One more style advice, please follow naming convention for Java, where variable names start with lowercase letter, with upper case letter for internal words (so, somethingLikeThis).
Programming isn't about getting things right, it's also about getting things readable. Learn and adopt a good coding style, and follow established conventions.
In the section in which you're doing your compareTo where the th value is not set. If this conditional is met, th can never be set to true.
Welcome!
I have a recursive public static method named less that takes a tree node (an original binary tree, not really a search tree) and a int parameter that returns if all the values in the tree are less than the integer. So, I would use a public class TN { public int value; public TN left, right; public TN(int v, TN l, TN r) {value = v; left = l; right = r;} }
So, my method would look like this:
public static boolean less(TN s, int toFind){
if (s == null)
return true;
else{
if(s.value <= toFind)
return less(s.left, toFind) && less(s.right, toFind); // right here do I return true? or do I have to somehow recall recursively
else
return false;
}
I was wondering if that was right or am I missing something??? Do I have to return true and false??
There are much more elegant, OO ways to write this. My recommendation would be to make less() a non-static member function of the TN class. That way, if the tree's root node is called root, you just call root.less(). Each call to less() will then call left.less() and right.less().
Since you posted example code that wouldn't even compile, I'm wondering if you're using an IDE, or even tried to compile your class using javac. I strongly recommend getting Eclipse, Netbeans, or another IDE if you're new to Java.
return less(s, toFind);
should be:
return less(s.left, toFind) && less(s.right, toFind);
I don't know why the function is static.
As mentioned before, your first part should just be:
if (s == null) return true;
(EDIT: This will let you get a true result when all nodes meet the condition. You have an == in there that should be a <).
EDIT: Ok, you've got a lot of problems than just those I mentioned. You need to logically step through your code.
You need to traverse your tree, so you'll need to call your function on your children nodes. Next, you need to return true as your default result. That way, when you reach a number greater than what you're looking for, you can return false immediately without traversing any of the children. I hope I've helped you enough with the logic for you to get through the rest of it yourself.
First, if (s = null) should be if (s == null) as you are doing a comparison, not setting the value of s to null.
The statement return less(null, toFind); keeps calling your method - you'll overflow your stack.
Notice how there's no way that your function could ever return true because every time you terminate the recursion, you're returning false? And the problem is in your first check. You say that "all the values in the tree are less than the integer." Well, in an empty tree, all the values (of which there are none) are indeed less than any integer, so you should return true in that case.
Also, while you say "less than", you're comparing for equality, so you're actually checking whether all the values are equal to the integer, not less than it.