I have a Node class. It has a children ArrayList. That list consists of Nodes as well. And said nodes have children lists, and so on.
Basically, it's a tree in somewhat not so convenient form. Let's say I want to delete someNode from it. So how to clear all of the child lists recursively?
I have a hasChildren() method, which returns if specified node has children, I think it has to help me, but can't figure out how yet. I've also got getChildren() method which returns list of children.
Here's some of my code, but it is wrong all over the place.
public void removeChild()
{
while(hasChildren())
{
getChildren();
removeChild();
}
children.clear();
}
You can implement a Queue which you can use to put every Node's children and then pop from it to remove them.
Something like this.
Queue<Node> queue = new LinkedList<>();
queue.add(node); //node to remove
while(!queue.isEmpty()) {
Node currentNode = queue.pop();
for(Node n : currentNode.getChildren) {
queue.add(n);
{
currentNode.getChildren.clear();
}
UPDATE: To do it recursively you could implement something like this (just be aware of stack size in java).
public void removeChildren(Node node)
{
for(Node n : node.getChildren()) {
removeChildren(n);
}
node.getChildren().clear();
}
In my opinion you just need to clear the children (as shown below) and the Garbage collector will automatically free rest of the objects.
public void removeChild()
{
if(hasChildren())
{
children.clear();
}
}
Related
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;
}
}
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.
I'm trying to do a depth first search in Java recursively. At the moment, the code runs through my graph fine, but it never backtracks to find a route when they're are no more nodes to visit. I'm having a bit of a mental block honestly. What would be the best way to go back to the parent node?
Here is my code so far:
private final Map<Character, Node> mNodes;
private final List<Edge> mEdges;
public DepthFirstSearch(Graph graph){
mNodes = graph.getNodes();
mEdges = new ArrayList<>(graph.getEdges());
for(Node node : mNodes.values()){
node.setVisited(false);
}
}
public void depthFirstSearch(Node source){
source.setVisited(true);
List<Node> neighbours = source.getNeighbours(mEdges);
for(Node node : neighbours){
if(!node.isVisited()){
System.out.println(node.getName());
depthFirstSearch(node);
}
}
}
And the getNeighbour code:
public List<Node> getNeighbours(List<Edge> edges) {
List<Node> neighbours = new ArrayList<>();
for(Edge edge : edges){
if(edge.getFrom().equals(this)){
neighbours.add(edge.getTo());
}
}
return neighbours;
}
Added code for trying Jager's idea:
public void depthFirstSearch(Node source){
source.setVisited(true);
List<Edge> neighbours = source.getNeighbouringEdges(mEdges);
for(Edge edge : neighbours){
if(!edge.getTo().isVisited()){
System.out.println(edge.getTo().getName());
depthFirstSearch(edge.getTo());
}else{
depthFirstSearch(edge.getFrom());
}
}
}
Well, typically you have a root node that has children. Each child can have children of its own. So you would rather do:
public void depthFirstSearch(Node source)
{
for(Node node : source.getChildren())
{
System.out.println(node.getName());
depthFirstSearch(node);
// and right here you get your back tracking implicitly:
System.out.println("back at " + node.getName());
}
}
Note that I do not have a necessity for a member visited...
Edit:
Now that you provided your data structure, let me propose another approach:
class Node
{
// all that you have so far...
private char mId;
private List<Node> mChildren = new ArrayList<Node>();
public char getId()
{
return mId;
}
public List<Node> getChildren()
{
return Collections.unmodifiableList(children);
}
// appropriate methods to add new children
}
The id replaces the key of your map. Then you simply have a root Node mRoot to start with somewhere. This is the typical way to implement trees.
You might want to go up from a child node directly. Then you'd additionally need a private Node parent; in the node class (immediately being set to this when adding a child to the private list and set to null, when being removed). You won't use this for backtracking, though, so the depth first search above remains unchanged.
Guessing: you are "getting" the neighbors for mEdges which seems to be a field of the surrounding class.
Most likely, you should ask each node for its own edges upon visiting it.
I am trying to iterate through a recursive object but Java has no support for this from what I know.
For example, given the object Item:
public class Item {
Long uuid;
List<Item> children;
}
With a for loop I could iterate through children but since children will contain more children which will contain more children and so on, there's no way to automatically determine the depth and loop based on that depth.
Is there a way to iterate through recursive objects?
If the tree is very deep, use a breath-first search as suggested by Eran. If the tree is very wide, use a depth-first search which could look something like:
class ItemVisitor {
public void accept(Item item) {
// Do something
for (Item i : item.getChildren()) {
this.accept(i);
}
}
}
EDIT:
For a breath-first search, use a queue and append all the children of the current node onto it.
public void visitTree(Item head) {
Queue<Item> queue = new PriorityQueue<Item>();
while (queue.size() > 0) {
Item curr = queue.poll();
// Do something
for (Item i : curr.getChildren())
queue.add(i);
}
}
If you don't have cycles within the parent-child tree you can use a simple recursive function to determine the number of descendants:
public class Item {
...
public int getDescendantCount() {
int count = 0;
if (children != null) {
count += children.size();
for (Item child : children)
count += child.getDescendantCount();
}
return count;
}
}
Something similar to this?
void read(Item item) {
if (item == null) {
//do something with the uuid ?
return;
} else {
for (Item i : item.children) {
read(i);
}
}
}
I don't know what the exact goal of the function is, but you can always loop recursively through children.
For example
public void loopChildren(List<Item> items) {
for (Item i : items) {
System.out.println(i.uuid);
loopChildren(i.children);
}
}
It just keep looping until the end of the list. If a child has no children List should be empty so it terminates for that iteration.
Hope this helps.
If you can store depth as a separate data item and enforce it via class design/encapsulation, you're good there.
What you're proposing is a node of some kind of tree of indeterminate depth. You can implement any normal depth-first or breadth-first search method; look it up in any standard data structures and algorithms textbook/web reference and implement in Java. The solution Eran posted while I was typing is a standard depth-first search if you use a Stack (last-in-first-out or LIFO queue), or a breadth-first search if you use a FIFO queue. These are nice and clean methods, but not the simplest.
The most naïve method would be a simple recursive function for a depth-first search:
public void recurseIntoChildren(Item item) {
if(item.children.size() == 0) {
// you are now at a leaf node: do something
}
for(Item child : item.children) {
recurseIntoChildren(child);
}
}
This form assumes you want to do something at leaf nodes. If you are searching for something, you can have recurseIntoChildren() return a special value when you find what you want so you can break out of all the rest of the recursive loops (let it return null or some other value to indicate the loop should continue). If you want to take other action, up to you to work this to your needs.
This is not the most efficient method (unless the compiler optimises tail recursion into a simple loop).
I have this linked list method that is used to insert before, so it takes a node and puts it before the beforeNode. Currently it does that, but then it goes on forever and makes the linked list infinitely big when it should only be four long. Does anyone see why it keeps on going?
private void insertBefore(Node aNode, Node beforeNode)
{
if(this.getPrevious(beforeNode) != null) {
this.getPrevious(beforeNode).setNext(aNode);
// aNode.setPrevious(beforeNode);
//this.getPrevious(this.getPrevious(beforeNode)).setNext(aNode);
} else {
head = aNode;
}
aNode.setNext(beforeNode);
// beforeNode.setPrevious(aNode);
}
Here is the print list method that could have something to do with it, but I dont think so
public void printList()
{
Node currentNode;
currentNode = this.getHead();
System.out.print("head ->");
while(currentNode!=null)
{
System.out.print(currentNode.getData().toString()+ " -> ");
currentNode = currentNode.getNext();
}
System.out.println("|||");
}
I think some how you are passing the same node for both aNode and beforeNode. In java, every object is a reference. Did you by any chance try to create aNode a copy of beforeNode ? It might have made both the same and causing the linked list to have a self loop. use a copy constructor or things like clone to get a duplicate node.