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
Related
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>)
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 2 years ago.
The code below shows a data structure in leetcode. We can see the node1 store a list with node2 and node3, node2 will store a list with node1 and node4. In this case I think node1 and node2 will store the object of each others, which will cause an infinite recursion. How does java store the data structure like this, doesn't it cause a memory exceed?
class Node {
public int val;
public List<Node> neighbors;
public Node() {
val = 0;
neighbors = new ArrayList<Node>();
}
public Node(int _val) {
val = _val;
neighbors = new ArrayList<Node>();
}
public Node(int _val, ArrayList<Node> _neighbors) {
val = _val;
neighbors = _neighbors;
}
}
public static void main(String[] args) {
Node node1 = new Node(1, new ArrayList<>());
Node node2 = new Node(2, new ArrayList<>());
Node node3 = new Node(3, new ArrayList<>());
Node node4 = new Node(4, new ArrayList<>());
node1.neighbors.add(node2);
node1.neighbors.add(node4);
node2.neighbors.add(node1);
node2.neighbors.add(node3);
node3.neighbors.add(node2);
node3.neighbors.add(node4);
node4.neighbors.add(node1);
node4.neighbors.add(node3);
Solution solution = new Solution();
solution.cloneGraph(node1);
}
You would be correct about this code causing memory to be exceeded if each node's list of neighbours contained copies of those neighbours. But that's not how Java works. Instead the list contains references to the neighbour nodes.
As an analogy, if each time you wrote down someone's address you need a complete copy of their house then you'd run out of space quickly. But you don't - you just need a reference to their house which can itself contain a reference to yours.
Note that's it's pretty easy to write code that causes a stack overflow with objects that contain references to themselves. For example, if your class had a method:
class Node {
public int sumVals() {
return val + neighbours.stream().mapToInt(Node::sumVals).sum();
}
}
calling node1.sumVals() will cause infinite recursion.
Try to create an empty link list. To creating the empty list I create a inner class Node and made it static such that main class can access it.
import java.util.LinkedList;
public class Addtwo {
static class Node {
int data;
Node next;
Node head;
Node(int d) {
data = d;
next = null;
// Constructor
}
public static void main (String args[])
{
/* Start with the empty list. */
LinkedList llist = new LinkedList();
llist.head = new Node(1);
Node second = new Node(2);
Node third = new Node(3);
llist.head.next = second;
second.next = third;
}
}
}
It cannot find the node head that I create within the inner class Node. How to solve this?
Error:
Error :(22, 22) java: cannot find symbol
symbol : variable head
location: variable llist of type java.util.LinkedList
First, if you want to use the JDK's LinkedList, you don't need to manage the nodes of the list, this work is already implemented. You only need to do this:
LinkedList<Integer> llist = new LinkedList<Integer>();
llist.add(1);
llist.add(2);
llist.add(3);
And there is more functionality here.
Second, if you want to implement your own linked list (I think this is what you want), you donĀ“t need to use the JDK's LinkedList, you can start with this basic code:
public class Addtwo {
static class Node {
int data;
Node next;
Node(int d) {
data = d;
next = null;
}
public static void main(String args[]) {
/* Start with the empty list. */
Node head = new Node(1);
Node second = new Node(2);
Node third = new Node(3);
head.next = second;
second.next = third;
Node iterator = head;
while (iterator != null) {
System.out.println(iterator.data);
iterator = iterator.next;
}
}
}
}
PS: You don't need to store a head for each node. You probably need another class LinkedListManager to implement some methods and store the head and the tail of the list.
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.
I'm learning about Lists in java but I'm having a hard time returning it from a method like I would any primitive data type. All I'm trying to do is return a list of nodes and then print out all their labels. What am I doing wrong?
import java.util.ArrayList;
import java.util.List;
public class TestingArrays
{
List<Node> myList1 = new ArrayList<Node>();
List<Node> myList2 = new ArrayList<Node>();
List<Node> myList3 = new ArrayList<Node>();
List<Node> myList4 = new ArrayList<Node>();
private Node Node1 = new Node("One", myList1);
private Node Node2 = new Node("Two", myList2);
private Node Node3 = new Node("Three", myList3);
private Node Node4 = new Node("Four", myList4);
public static void main(String arg[])
{
List<Node> nodeList = nodeArray();
for (int i = 0; i < nodeList.size(); i++)
{
System.out.println(nodeArray.get(i).label);
}
}
public List<Node> nodeArray()
{
List<Node> tempList = new ArrayList<Node>();
tempList.add(Node1);
tempList.add(Node2);
tempList.add(Node3);
tempList.add(Node4);
return tempList;
}
}
you can't call non static method from static context. make method nodeArray() static. That'll fix your problem.
also you cannot make a static reference to the non-static field i.e. Node1, Node2, Node3, Node4. so make them static too.
also nodeArray.get(i).label is wrong as it should be nodeList.get(i).label.
this is weird:
nodeArray.get(i)
nodeArray is a function . how could it even compile? that's why it's important to give good names to both functions and variables.
also , since it's a list , you can use foreach , like this:
http://www.leepoint.net/notes-java/flow/loops/foreach.html
oh , and in the main function you should either create a new instance of the class and use it , or set all of the methods and variables as static.
The nodeArray() method is a method for the TestingArrays object. All the nodes and lists are attributes of the TestingArrays object.
You need to create a TestingArrays object to access those things.
Replace your main method with this code:
public static void main(String arg[])
{
List<Node> nodeList = new TestingArrays().nodeArray();
for (int i = 0; i < nodeList.size(); i++)
{
System.out.println(nodeList.get(i).label);
}
}