I was trying to implement a class Node to build a tree of Nodes. Basically, each Node can have children, so if I specify multiple nodes I can build a tree out of it.
As an example:
node1 (the root) has node2 and node3 as children
node2 has node4 and node5 as children
The problem I am having problems to solve is to build this tree and find all children of a given element (in this case node1 would have 4 children, since it has node2 and node3 in the first place, and node2 has 2 children, so in total 4).
Does anyone have any suggestion?
EDIT:
package ex1;
import java.sql.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Node {
private String name;
private String description;
private ArrayList<Node> children = new ArrayList<>();
Node(String name, String description){
this.name = name;
this.description = description;
}
private void setName(String name){
this.name = name;
}
private void setDescription(String description) {
this.description = description;
}
public void addChildren(Node child) {
this.children.add(child);
}
public String getName() {
return this.name;
}
public String getDescription() {
return this.description;
}
public boolean hasDescription() {
return !description.isEmpty();
}
public Collection<Node> getChildren() {
return this.children;
}
/*
public Node findNodeByName(String name, Node t) {
if (t.getName().equals(name))
return t;
t.getChildren().forEach(node -> node.findNodeByName(name,node));
return null;
}*/
public Node findNodeByName(String name, Node t){
if(t.getName().equals(name)){
return t;
}
else if (t.getChildren().size() != 0){
for(Node c: children){
Node ret = c.findNodeByName(name,c);
if(ret != null){
return ret;
}
}
}
return null;
}
// IMPORTANT: Don't change this method!
private String toString(int indentNo) {
String indent = "t".repeat(indentNo);
StringBuffer b = new StringBuffer();
b.append(indent);
b.append(getClass().getSimpleName() + " '" + getName() + "' ");
if (hasDescription()) {
b.append("(description: " + getDescription() + ")");
}
b.append("n");
for (Node node : getChildren()) {
b.append(node.toString(indentNo + 1));
}
return b.toString();
}
@Override
public String toString() {
return toString(0);
}
}
Method where I make use of the class:
Path path = Path.of(pathname);
String fileContent = null;
try {
fileContent = Files.readString(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
List<String> lines = new ArrayList<>(Arrays.asList(fileContent.split("n")));
String[] firstLine = lines.get(0).split(",");
Node parentNode = new Node(firstLine[0], firstLine[1]);
lines.remove(0);
/* This was just to test findNodeByName
for(String line: lines) {
String[] params = line.split(",");
System.out.println(params[2] + ": " + (parentNode.findNodeByName(params[2], parentNode) != null));
}*/
//Now we read all remaining data
Node tmpNode;
for(String line: lines) {
String[] params = line.split(",");
if (parentNode.findNodeByName(params[2])==null || parentNode.findNodeByName(params[0])!=null) //if parent was not found or name already exists
throw new IOException();
tmpNode = parentNode.findNodeByName(params[2]);
tmpNode.addChildren(new Node(params[0],params[1]));
}
CSV file I am getting the data from:
uni,"This is my university folder",
firstyear,,uni
secondyear,,uni
analysis,"folder for the analysis course",firstyear
ai,"folder for the artificial intelligence course",secondyear
db,"folder for the database course",firstyear
3
Answers
Here is some sample code that could help (explanation below):
Main class:
Node class:
Output:
Ok so in our node class, let’s say each node will have an integer value,
val
. That is our first private instance variable. Second, each node will have a list of children nodes,children
.When we first declare our nodes, they will have integer values, as shown in our constructor.
After we define our nodes, we can add some nodes as children to other nodes (v2 and v3 are children to v1, and v4 and v5 are children to v2).
Now we need to print them. We will use a recursive approach for this. If the node we are printing the children of has children (the length of our children ArrayList is nonzero), then we will first iterate through that list, and print out the children of our current node. Afterwards, we again iterate through each child and use the same method (recursion) to print out the children of that node.
I hope this helped! Please let me know if you need any further help or clarification 🙂
EDIT:
Added a
getName()
method:Added the requested method:
Quick Explanation: Very similar to the original method, we use a recursive approach to iterate through each nodes’ children: Once we reach a node with no more children, we return null. Once we reach the node with the given value, we return a copy of that node, which will be sent back to wherever the function was called..
Also edited main method:
Output:
SECOND EDIT:
Change the method to look like this:
The main method should look like this:
Output:
THIRD EDIT:
Added a new method:
Edited method:
Main Method:
Output:
As per your requirement, you are looking for all descendants / children-of-children of a particular node. Then breadth-first depth-search is fit more to this use case. There are already tons of discussions around these algorithms. For instance:
Breadth First Search and Depth First Search
You are already thinking in the right direction related to its DataStructure. One thing I would suggest use java generics so that it can support multiple data-type as needed.
The return value of the recursive method call is dismissed.
The line
induces the recursive invocation, but the return value is not used to form the return value of the enclosing method.
Instead we need something like
or with streams