I am new to using recursion for my methods. I tend to steer away from them for quite a few reasons. However, for a project, it seems to easier to have a recursive method instead of a looping one since I am trying to do Depth First Traversal for a Graph.
Since I am not too well versed in recursion, I don't understand why I am getting the following error.
This method must return a result of type LinkedList.Node
The code I have currently is:
public Node DFSTime(Node node){
if(node == null){
System.out.println("No path found");
return null;
}
else if(node.element.equals(destinationAirport)){
return node;
}
else{
stack.push(node);
DFSTime(node.nextNode);
}
}
It is unfinished code since I still need to implement some logic, however, I don't understand how to eliminate the error. Is there something very basic that I am missing?
The reason of the compilation error is pretty trivial. The compiler clearly tells that didn't provide the result to return for all possible cases.
The more important is that your current approach is not correct.
it seems to easier to have a recursive method instead of a looping one since I am trying to do Depth First Traversal for a Graph
There are crucial things to consider:
Field nextNode is very suspicious. If each Node holds a reference pointing to a single node only, in fact the data structure you've created by definition isn't a Graph, but a Singly linked list. And doesn't make sense to implement DFS for a list. Every node should point to a collection of nodes, no to a single node.
You have to distinguish somehow between unvisited nodes and nodes that are already visited. Or else you might and up with infinite recursion. For that, you can define a boolean field isVisited inside the Node, or place every visited node into a HashSet.
Since you've chosen to create a recursive implementation of DFS, you don't need to create a stack. It's required only for iterative implementation.
Don't overuse global variables. I guess you might want to be able to check whether it is possible to reach different airports of destination without reinstantiating the graph.
Use getters and setters instead of accessing fields directly. It's a preferred practice in Java.
Your method might look like this (it's not necessary that element should be of type String it's just an illustration of the overall idea):
public Node DFSTime(Node node, String destinationAirport){
if(node == null || node.isVisited()) {
return null;
}
if (node.getElement().equals(destinationAirport)) {
System.out.println("The destination airport was found");
return node;
}
node.setVisited(true);
for (Node neighbour: node.getNeighbours()) {
Node result = DFSTime(neighbour, destinationAirport);
if (result != null) return result;
}
return null;
}
And the node might look like this:
public class Node {
private String element;
private List<Node> neighbours;
private boolean isVisited;
public Node(String element, List<Node> neighbours) {
this.element = element;
this.neighbours = neighbours;
}
public void setVisited(boolean visited) {
isVisited = visited;
}
public boolean isVisited() {
return isVisited;
}
public void addNeighbours(Node neighbour) {
neighbours.add(neighbour);
}
public String getElement() {
return element;
}
public List<Node> getNeighbours() {
return neighbours;
}
}
You should have a default return statement at the end of the function after the closing of the else.
In methods conditional blocks (if-else), you need to make sure you are returning appropriate Type from all conditional statements, so that there is no compile-time error. In your case, else block is recursively calling DFSTime(..) without returning anything.
You might want to return reference which gets called via recursive call, something like below:
public Node DFSTime(Node node){
if(node == null){
System.out.println("No path found");
return null;
}
else if(node.element.equals(destinationAirport)){
return node;
}
else{
stack.push(node);
Node node = DFSTime(node.nextNode);
return node;
}
}
Related
I have the following code to insert into the binary tree:
public void insert(T item) {
root = insert(item, root);
}
private Node insert(T item, Node node) {
if(node == null){
return new Node(item, null, null);
} else {
if(item.compareTo(node.item) > 0) {
node.rightChild = insert(item, node.rightChild);
} else {
node.leftChild = insert(item, node.leftChild);
}
}
return node;
}
the code works fine, I have tested it
my question is, how come the root is never changed since in the public function I assigned the returned node from the private function to the root
Thank you!
The public insert is just an interface into the recursive method which rebuilds the tree as the stack unwinds ending where you started, at the root (root = ...). Except for the first insert, you go left or right until you insert at the leaf level. Without any balancing, you will have the same root (assuming no removals) for the lifetime of the tree. Therefore, the only time the root changes on insert is when it's empty.
Note: There's also a matter of what happens when a node is inserted with an existing value; do you discard it, allow duplicates, or swap the objects? That's an implementation detail.
I read your code again and your code is correct. The return value is always the root element because your frist function call is insert(item, root) and the return value is what you give.
I am trying to write a method which recursively deletes a node from a binary search tree. I understand the algorithm, but my code is currently returning an error. When I try to delete a leaf node, i.e. a node which has no children, it deletes that node but also the topmost node of the tree.
I already have methods which to find the head of a node, getValue(), as well as finding the left and right subtrees, getLeft() and getRight(). I also have the method isEmpty() which checks to see if a tree is empty.
This is my code currently, where x is the node to be deleted and a is a binary search tree:
public static Tree delete(int x, Tree a) {
if (a.isEmpty()) {
return new Tree();
} if (x>a.getValue()) {
return delete(x, a.getRight());
} else if (x<a.getValue()) {
return delete(x, a.getLeft());
} else {
if (a.getLeft().isEmpty()&&a.getRight().isEmpty()) {
return new Tree();
} if (a.getRight().isEmpty()) {
return delete(x, a.getLeft());
} if (a.getLeft().isEmpty()) {
return delete(x, a.getRight());
} else {
return new Tree(); //not yet completed
}
}
}
Can anyone give me any clues as to why this would be happening? Thanks in advance
Edit: Here is the code which eventually worked if anyone happens to stumble across this question
public static Tree delete(int x, Tree a) {
if (a.isEmpty()) {
return new Tree();
} if (x>a.getValue()) {
return new Tree(a.getValue(), a.getLeft(), delete(x, a.getRight()));
} else if (x<a.getValue()) {
return new Tree(a.getValue(), delete(x, a.getLeft()), a.getRight());
} else {
if (a.getLeft().isEmpty()&&a.getRight().isEmpty()) {
return new Tree();
} if (a.getRight().isEmpty()) {
return new Tree(a.getLeft().getValue(), delete(a.getLeft().getValue(), a.getLeft()), a.getRight());
} if (a.getLeft().isEmpty()) {
return new Tree(a.getRight().getValue(), a.getLeft(), delete(a.getRight().getValue(), a.getRight()));
} else {
return new Tree(max(a.getLeft()), delete(max(a.getLeft()), a.getLeft()), a.getRight());
}
}
}
This method returns an empty tree instead of setting left or right as empty. This is why you think it's deleting the top node. Also it doesn't look like it handles deleting the node itself, only child nodes.
You never actually delete anything. There are two ways to do this.
Making a structureal copy of the tree until the node to be deleted and then take one of the children and insert the other to the chosen child the result of the insert is the result of the tree.
Finding the parent of the node to be deleted and mutate the accessor to the node to be one of the children and then add the other child subtree to the parent tree. Basically here you have a tree class that handles insertion and which has a root. Deleting the root is a special case with rebinding instead of altering a node.
If you are making a backtracking algorithm where going back to a previous tree is needed #1 is the only choice and it will share as much structure with the previous version of the tree. If you want to iterate and update a data structure to reflect something where you never need th eprevious state #2 is the best choice.
Here is the code for the implementation of the Binary Search Tree:
public class BST<T extends Comparable<T>> {
BSTNode<T> root;
public T search(T target)
{
//loop to go through nodes and determine which routes to make
BSTNode<T> tmp = root;
while(tmp != null)
{
//c can have 3 values
//0 = target found
//(negative) = go left, target is smaller
//(positive) = go left, target is greater than current position
int c = target.compareTo(tmp.data);
if(c==0)
{
return tmp.data;
}
else if(c<0)
{
tmp = tmp.left;
}
else
{
tmp = tmp.right;
}
}
return null;
}
/*
* Need a helper method
*/
public T recSearch(T target)
{
return recSearch(target, root);
}
//helper method for recSearch()
private T recSearch(T target, BSTNode<T> root)
{
//Base case
if(root == null)
return null;
int c = target.compareTo(root.data);
if(c == 0)
return root.data;
else if(c<0)
return recSearch(target, root.left);
else
return recSearch(target, root.right);
}
Why do I need the recursive helper method? Why can't I I just use "this.root" to carry out the recursive process that is taking place? Furthermore, if screwing up the root property of the object this method is being called on is a problem, then how is does the helper method prevent this from happening? Does it just create a pointer that is separate from the this.root property, and therefore won't mess up the root property of the object that the method is being called on?
Sorry if the question doesn't seem straight forward, but if anyone can enlighten me on what's exactly going on behind the scenes I would really appreciate it.
The method needs a starting point. It needs to have a non changing Target node and it needs to compare it with some other node to see if they are a match lets call this node current instead of root since it is the current Node the recursive method is evaluating. There really isn't a concise way of doing this when using a recursive method other than using a helper function and passing in both variables (this is the case for many recursive methods). As you said stated if you updated root you would completely alter your tree when going left or right which you wouldn't want to do. The helper function is used because it gives your recursive method a starting point. And it also keeps track of the current node you are working on as you said the method points to the Node object being evaluated but doesn't make any changes. When going left or right it doesn't modify anything it just passes in a reference to the left or right node and continues to do this until the target is found or the base case is hit.
I've been tasked with finding and returning a particular node from a general tree given by the string targetName. Take a look at my implementation below:
public GeneralTreeNode findNode(String targetName) {
if (this.name.equals(targetName)) {
return this;
} else {
for (GeneralTreeNode child : this.children) {
return child.findNode(targetName);
}
}
// no node containing the string could be found
return null;
}
The only problem is that this too often seems to incorrectly return null when in fact a node does exist. It's as if the last line, return null, is too greedy.
Chucking a few breakpoints on this and watching it shows it only seems to go down to the lowest depth until a node has no children, in which case it simply returns null.
Can anyone offer suggestions on how to improve this?
Change your code to this:
public GeneralTreeNode findNode(String targetName) {
if (this.name.equals(targetName)) {
return this;
} else {
for (GeneralTreeNode child : this.children) {
GeneralTreeNode childResult = child.findNode(targetName);
if (childResult != null) {
return childResult; // only return if you really found something
}
}
}
// no node containing the string could be found
return null;
}
You only want to return the result from the child search if it really found something.
The readability of the code disappears if you implement in this way. Tree-traversal would be better implemented in an helper class and you pass the ROOT element with the target_name together.
If you return null in this way, it is something like node is null actually it is not. On the other hand, when you use "doer" or "processor" method/function, it can return true saying "I cannot find anything".
Still, your code seems ok. I just rewrite it.
static Node search(Node node, String nodeName) {
if (node.getName().equals(nodeName)) return node;
List<Node> children = node.getChildren();
foreach(Node child : children) {
Node resultChild = search(child, nodeName);
if (resutlChild != null) return resultChild;
}
return null;
}
I am having problems trying to check if a value is in a linked list or not using recursion. The values in the linked list are between 0 and 5. If the value is in the linked list, the method should return true. However, I am getting wild answers across the board if the value is indeed in the linked list. Some numbers will return false, and some will return true. I am not sure why it is doing this. Thanks!
public boolean contains(int aData)
{
Node currentNode = firstNode;
if(currentNode == null) {
return false;
}
if(currentNode.data == aData) {
return true;
}
else {
return false;
}
}
You're only checking one node (the first node). You're going to be needing something like this:
public boolean contains(int aData, Node node)
{
Node currentNode = node;
// base case; if this node is null, return false
if(currentNode == null) {
return false;
}
// if this node contains the data, return true, otherwise, check next nodes.
if(currentNode.data == aData) {
return true;
} else {
return contains(aData, currentNode.next);
}
}
You can call the above function starting with the head node
contains(5, headNode);
and it will run through your entire list until either a) it finds the data, or b) it has exhausted all options and the data was not found.
As has been mentioned, you are not using recursion and are only checking the first Node. If you want to use recursion, you'll need to call the contains method from within the contains method, which you are not currently doing. Even if you were to simply call it at the end of the method as it stands now, it still wouldn't do anything - think about how you might rewrite it if the method started:
public boolean contains(int aData, Node nodeToCheck)
Recursion has a very well defined form that is used in almost all cases. Essentially the form is:
type method(context) {
if (one of the base cases holds)
return appropriate base value
else
for each possible simpler context
return method(simpler context);
}
This works by progressively breaking the problem down into smaller pieces until the problem is so simple it has an obvious answer (i.e. the base case). The key to using recursion is to ask yourself 'in what situations is the answer obvious?' (i.e. the base cases) and 'when the answer isn't obvious how can I simplify the situation to make it more obvious?'. Don't start coding until you can answer those questions!
In your case you have 2 base cases: you've reached the end of your list or you have found the value. If neither of those cases hold then try again in a simpler context. In your case there's only one simpler context: a shorter list.
Putting all that together you have:
public boolean contains(Node node, int data) {
if (node == null)
return false;
else if (node.value == data)
return true;
else
return contains(node.next, data);
}