Create child nodes using recursion - java

I'm trying to create a hierarchy from flat data. I have the following Node definition:
public class Node {
public String name;
public List<Node> children = new ArrayList<>();
}
Given this data: [Person,Manager,Hourly,New], where the tree should be like:
Person
|--Manager
|--Hourly
|--New
I've tried the following:
public void run()
{
List<List<String>> objects = new ArrayList<>();
String[] str = {"Person","Manager","Hourly","New"};
objects.add(Arrays.asList(str)) ;
String[] str2 = {"Person","Manager","Salary"};
objects.add(Arrays.asList(str2)) ;
String[] str3 = {"Person","Manager","Salary", "New"};
objects.add(Arrays.asList(str3)) ;
// Create a Node with the sequence
myNode = new Node();
createNode(objects.get(0), 0, myNode, myNode);
LOG.debug(myNode.name);
}
And my createNode method is:
public Node createNode(List<String> seq, Integer start, Node parentNode, Node childNode)
{
// do something and return a Node?
}
But conceptually I don't understand how to maintain the structure if Java is return-by-value. What do I add to createNode so that I can add a Manager->Hourly->New hierarchy as a child to Person

You don't need both a Node return type and a Node argument to your method.
Here's one way to do it:
//in run()
myNode = new Node();
myNode.name = "Root";
createNode(objects.get(0), 0, myNode, myNode);
public void createNode(List<String> seq, Integer start, Node parentNode)
{
Node childNode = new Node();
childNode.name = seq[start];
parentNode.children.Add(childNode);
createNode(seq, start+1, childNode);
}
You don't need to return anything from createNode() -- since you have parentNode as a variable, you can add things to its children member. A call to createNode() will recursively add child nodes, following your string array to its end.
Another way to do it is like this:
public Node createNode(List<String> seq, Integer start)
{
if (start >= seq.Length) {
return null;
}
Node node = new Node();
node.name = seq[start];
node.children.Add(createNode(seq, start+1);
return node;
}
In this case, you don't need to pass in node references at all; calling createNode() will generate a new node object, fill its children tree recursively, and return the newly-generated node structure.

As I can see your defination of node is somewhat similar to adjacency list in graph.
In the Target node add the associated node in the list associated with the target node. This is true for each node belonging to all the nodes.
For each object belonging to the objects array (array parameter) in your createNode method, you need to create the Node object.
just pass an String array and the taeget node. Iterate the list and create a node. Add the node in the list.
To avoid duplicates while creating Node add them in an map. Key to the map should be String and value should be Node object. Before creating the object of node just try to get the object from the map, make the object only iff the object is not found in the map(in such a case create and add it to the map). In case object is found un the map, us the samedo not recreate it.

Related

Why LinkedList clone method implementation needs to store the copyied list into virgin state?

public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
This is the source code of LinkedList. The clone already has the elements in the original list, what is the purpose of making it empty and assigning the elements again?
The way that a java.util.LinkedList is implemented, is that it uses Node<E> objects to link elements together. And a LinkedList object has a reference to the first and last Node<E> in the list.
If you scroll around a bit you'll find this declaration:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Visually, a LinkedList with 4 elements can be thought of like this:
When cloning a linked list, what we would expect to happen is that the entire chain of Nodes is copied. Like this:
However, superClone just calls super.clone, which does not make copies of these Node objects. It only copies the LinkedList object. Therefore, it would be incorrect to implement LinkedList.clone by just calling super.clone, because then the cloned list would use the same chain of Nodes as the original:
This would mean that adding something in the middle of the chain would add that thing to both the cloned list, and the original list!
By resetting the cloned list to its initial state, and then re-adding all the elements from the original list, we create a new chain of Node objects for the cloned list. This is because add creates new Node objects:
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
The purpose of the clone method is returning a copy of the instance object. They correct meaning of copy is delegated to the implementor class, but main requirement is when
object.clone() != x, it returns true.
In the case of the Java LinkedList, it returns a shallow copy of the elements, but not a copy of the elements theirslef. In this case the list.clone() != list, it's still true, but when you check their elements is going to return false (example list.get(0) != list.clone().get(0)).
The purpose of the copied list is to be not linked to the original one, so you could add/insert/delete elements without modify the original list.
Example (pseudo-code):
original.add(1);
original.add(2);
original.size(); // 2
clonedList = original.clone();
clonedList.size(); // 2
clonedList.add(3);
clonedList.size(); //3
originalList.size(); //2

How to build an n-ary tree having same structure as another created one?

I am trying to build this n-ary tree having the same structure as an already build one (when creating the new tree to be returned i would like to add the child nodes in the same positions as in the already built one , the built tree is created as follows :
Node A = new Node("","A");
Node B = new Node("","B");
Node C = new Node("","C");
...
Node root = A;
root.children.add(B);
root.children.add(C);
root.children.add(D);
root.children.get(1).children.add(G);
root.children.get(1).children.get(0).children.add(K);
...
The Node Class is like the following :
public class Node {
public String id;
public ArrayList<ArrayList<String>> data;
public Vector<Node> children = new Vector<>();
public void setId(String id) {
this.id = id;
}
public void setData(ArrayList<ArrayList<String>> data) {
this.data = data;
}
public void setChildren(Vector<Node> children) {
this.children = children;
}
public Node(ArrayList<ArrayList<String>> data, String id) {
this.data = data;
this.id = id;
}
public Node(ArrayList<ArrayList<String>> data,String id,Vector<Node> children) {
this.data = data;
this.id = id;
this.children = children;
}
public Node find_parentNode(String childId) {
if (this == null)
return null;
Queue<Node> queue = new LinkedList<>();
// we add start node
queue.add(this);
// iterate while queue not empty
while (!queue.isEmpty()) {
// dequeue and print data
Node next = queue.remove();
for (Node child : next.children) {
if (child.id == childId)
return next;
queue.add(child);
}
}
return null;
}
And finally the main code is the following :
// Create rootOut (the root node to be returned)
Node rootOut = new Node(node.data,node.id,node.children);
queue.add(node);
// iterate while queue not empty
while(!queue.isEmpty()){
// dequeue
Node next = queue.remove();
// we add children nodes if not null after setting an increment var for the children positions
int j =0 ;
for (Node child : next.children) {
// Update children of rootOut (the output Tree)
Node currentNode = rootOut.find_parentNode(child.id);
currentNode.children.get(j).setChildren(child.children);
currentNode.children.get(j).setData(child.data);
currentNode.children.get(j).setId(child.id);
j++;
queue.add(child);
}
}
Basically in the main code, Instead of creating a new tree i override the values of the nodes of the built tree after having copying the old built tree into a new one (through root node rootOut),
Is it a good approach ? otherwise how to create a brand new tree with the same structure (nodes positions) as the built tree ?
Thanks.
To duplicate the structure of an existing tree it's enough to do a depth first traversal, copying each node and adding each children in the same traversal order.
You don't need to find the parent node, that is an expensive search, since the node will be added to the right parent in the previous call of the method.
I cannot test your code, since something is missing (e.g. what is QueryNode?), but it appears to copy only the root node, without actually copying the tree structure.
So this method will recursively duplicate the tree, the only shared resources between the new and the old tree are the data ArraList, where only the reference is copied.
public static Node cloneNode(Node root) {
Node copy=new Node(root.data, root.id);
for (Node c: root.children) {
copy.children.add(cloneNode(c)));
}
return copy;
}
As answer to your last comments, a deep copy of the data is not usual, but if you really want it just replace the first line of the method with these:
ArrayList<ArrayList<String>> copyData=new ArrayList<>();
for (ArrayList<String> l: root.data) {
copyData.add(new ArrayList<String>(l));
}
Node copy=new Node(copyData, root.id);
Some unrelated remarks:
Do not use Vector, use ArrayList instead
In method signature and variable declaration better use the List interface insted of the concrete ArrayList class (e.g. data should be declared as List<List>)

How to avoid the passing object after cloning in Java? [duplicate]

This question already has answers here:
How to clone ArrayList and also clone its contents?
(21 answers)
Closed 3 years ago.
I have a Node object and want to make some clone objects from this orginal one. Below is my code:
public class Main {
public static void main(String[] args) {
Node node = new Node();
node.setName("node1");
node.setValue("1");
node.setChildNodes(new ArrayList<>());
Node node2 = cloneNode(node);
Node childNode2 = new Node();
childNode2.setName("childNode2");
childNode2.setValue("1");
List<Node> childNodes2 = node2.getChildNodes();
childNodes2.add(childNode2);
node2.setChildNodes(childNodes2);
System.out.println(node.getChildNodes());
}
private static Node cloneNode(Node node) {
Node newNode = new Node();
newNode.setName(node.getName());
newNode.setValue(node.getValue());
newNode.setChildNodes(node.getChildNodes());
return newNode;
}
}
class Node {
private String name;
private String value;
private List<Node> childNodes;
//getter and setter
}
I created a first Node and create a second Node which is cloned from the first one. Then I would like to modify the childNodes list in the second Node object (node2) and then I realize that the childNodes list in the first Node(node) is also modified.
How can I avoid the list in the first Node being modified?
Thank you so much!
What you have done is a kind of shallow clone. You might want to clone deeper instead of
newNode.setChildNodes(node.getChildNodes())
You should clone the child nodes as well. Proper way is this
Alternatively , you can just serialize and deserialize the object is the easy way of cloning deep objects
Eg: Just transform the Node1 to JSON string and convert the string back to Node2 (Tip: use the gson library)

How to traverse an object array which has elements of the same object

public class Node{
private String name;
private Node parent;
private Node[] children; // no holes allowed like HW1
final int maxChildren=10;
}
The Node[] children contains other nodes which also have children nodes. How can I traverse all the "Node" elements in every Node within this tree.
How to traverse an object array which has elements of the same object
It will be a recursive one. To do a depth-first traversing, visit each node, let each node perform a traversing:
public void traverse(){
//do what you need for the current node
//For e.g, print the name
for(int i=0; i<children.length; i++)
children.traverse();
}

NullPointerException when adding node objects to an ArrayList [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I'm getting a NullPointerException when I try to run this code. I've assigned Nodes 2,3,and 4 as children nodes to Node1. I tried to create a method that will go through all the children nodes in Node1 and return the list. I'm not sure what I'm doing wrong.
public class TestingArrays2 {
List<Node> myList1;
List<Node> myList2;
List<Node> myList3;
List<Node> myList4;
private Node Node1;
private Node Node2;
private Node Node3;
private Node Node4;
public TestingArrays2() {
myList1 = new ArrayList<Node>();
myList2 = new ArrayList<Node>();
myList3 = new ArrayList<Node>();
myList4 = new ArrayList<Node>();
myList1.add(Node2);
myList1.add(Node3);
myList1.add(Node4);
Node1 = new Node("One", myList1);
Node2 = new Node("Two", myList2);
Node3 = new Node("Three", myList3);
Node4 = new Node("Four", myList4);
List<Node> allNodesArray = nodeArray(Node1);
for (int i = 0; i < allNodesArray.size(); i++){
System.out.println(allNodesArray.get(i).label);
}
}
public static void main(String arg[]) {
TestingArrays2 testArray = new TestingArrays2();
}
public List<Node> nodeArray(Node n){
List<Node> tempList = new ArrayList<Node>();
for (int i = 0; i < n.children.size(); i++){
tempList.add(n.children.get(i));
}
return tempList;
}
}
You're not creating your Nodes. See these lines...
private Node Node1;
private Node Node2;
private Node Node3;
private Node Node4;
These just declare a variable as being able to contain an object of type Node. However, they initially start with a null value - ie they're empty.
You're then calling these lines...
myList1.add(Node2);
myList1.add(Node3);
myList1.add(Node4);
Which would insert null values into your List, because you're trying to add an object that hasn't been created yet.
So, you need to change your code so that these lines...
Node1 = new Node("One", myList1);
Node2 = new Node("Two", myList2);
Node3 = new Node("Three", myList3);
Node4 = new Node("Four", myList4);
appear before you try to myList1.add() them to the list. This will create the Node objects first, which can then be added to your List.
As #BalusC mentioned in the comments, it is failing on your for loop later in your code, because it is trying to call .label on a null object. Correcting the order as suggested above will correct this, as all the objects in your List will now be Nodes.
This:
myList1.add(Node2);
myList1.add(Node3);
myList1.add(Node4);
Node1 = new Node("One", myList1);
Node2 = new Node("Two", myList2);
Node3 = new Node("Three", myList3);
Node4 = new Node("Four", myList4);
You are trying to add the nodes to the list before they have been created.
A good answer to your question is already given.
Looking at your code I have several suggested modifications.
You are doing all the work in (the constructor of) your test class. It is nicer design to delegate this to the Node class where possible. Also try not to do 'work' in the constructor, just initialization.
Also check out the code conventions I applied like using nouns for class names and starting variable names with a lower case letter.
public class ArrayTest2 {
public static void main(String arg[]) {
Node node1 = new Node("One");
node1.add(new Node("Two"));
node1.add(new Node("Three"));
node1.add(new Node("Four"));
// this calls the toString method of node1
System.out.println(node1);
}
}
public class Node {
private final String name;
private final List<Node> children;
public Node(String name) {
this.name = name;
this.children = new ArrayList<Node>();
}
public String getName() {
return name;
}
public void add(Node children) {
children.add(child);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name);
if(children.size() > 0) {
sb.append("(");
String separator = "";
for (Node child : children){
sb.append(separator).append(String.valueOf(child));
separator = ",";
}
sb.append(")");
}
return sb.toString();
}
}
Notice that the children field is private and there is no getter for it. It is considered bad practice to offer direct access to internal data structures like 'children' so I provided an 'add' method for adding nodes. In this way the class keeps control over what happens to its data, which is an important OO design principle.
The toString method builds a string representation of a Node. It appends the Node name and then, in case there are children, appends each child node's string representation in a comma-separated list surrounded by parentheses, so this should print something like:
One(Two,Three,Four)
A more complex structure for example:
Node node1 = new Node("One");
Node node2 = new Node("Two");
Node node3 = new Node("Three");
Node node4 = new Node("Four");
Node node5 = new Node("Five");
Node node6 = new Node("Six");
node1.add(node2);
node1.add(node3);
node2.add(node4);
node4.add(node5);
node4.add(node6);
Should give:
One(Two(Four(Five,Six)),Three)
Disclaimer: my code is hand-crafted, uncompiled and untested

Categories