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)
Related
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.
My teacher has assigned a program where I am to create a linked list of some random numbers. I am to create it from a list and then the second part of the assignment is to reverse it. The actual quote is
Write a Java method called reverseLinkedList() that will generate a
reversed linked-list from the linked-list that you create in problem
1. Your method should accept a linked-list as an input and return another linked list that has the node references in the reversed
order. Please do not print the original list in reverse. The idea is
to manipulate the node references so that the nodes are preserved in
same in order as they were originally created.
The code I have generated so far looks like
import java.util.*;
public class progassignment2
{
public static void main(String args[])
{
List<Integer> myList = new ArrayList<Integer>();
Random ran = new Random();
int ranNum;
for(int x = 0;x<5;x++)
{
ranNum = ran.nextInt(500);
myList.add(x,ranNum);
}
LinkedList<Integer> mylinklist = createLinkedList(myList);
System.out.println(mylinklist);
LinkedList<Integer> mylinklistrev = reverseLinkedList(mylinklist);
}
public static LinkedList createLinkedList(List<Integer> integerList)
{
LinkedList<Integer> linkedlist = new LinkedList<Integer>();
linkedlist.addAll(integerList);
return linkedlist;
}
public static LinkedList reverseLinkedList(LinkedList inputList)
{
for(int y = 0;y < inputList.size();y++)
{
inputList.addLast(inputList.pollFirst());
}
return inputList;
}
}
However I don't think I'm doing the assignment correctly, or that I understand what he is asking of me and unfortunately won't answer any questions and just cites "Read the assignment". Any help is greatly appreciated
What about:
public static LinkedList reverseLinkedList(List<Integer> inputList) {
LinkedList<Integer> reversedLinkedlist = new LinkedList<Integer>(inputList);
Collections.reverse(reversedLinkedlist);
return reversedLinkedlist;
}
Usually, exercises on linked lists do not make use of any built-in Java collection (like ArrayList, LinkedList, etc), but are instead meant to make you build your own collection type.
Your teacher probably wants you to build a very basic element, which would then become the building block of your own collection type: imagine an object where you can store a value and a reference to the following value in the list. In code:
class Node {
private int value;
private Node next;
public Node(int value){
this.value = value;
}
public int getValue(){
return value;
}
public Node getNext(){
return next;
}
public void setNext(Node next){
this.next = next;
}
}
Each element points to the next one, and the end of the list is marked by the last node's next element being null.
By using objects like this, you'll be able to define your own linked list, without using any pre-defined Collection offered by Java.
You've surely heard about the stack data structure: by reading all the elements in your linked list and putting them inside a stack, once the list will be over, you're going to fetch the elements inside the stack; creating a linked list in the order of the elements pulled from the stack will solve your problem of inverting the linked list.
The idea is to manipulate the node references so that the nodes are
preserved in same in order as they were originally created.
You should create your own LinkedList. You are not allowed to use common ways of reversing like using recursion, stack ,modifications or any collections interface methods.
here is the link includes LinkedList reversing ways and solution:
class LinkedList {
Node head; // head of list
/* Linked list Node */
class Node {
int data;
Node next;
Node(int d) {
data = d;
next = null;
}
}
/* Function to print reverse of linked list */
void printReverse(Node head) {
if (head == null)
return;
// print list of head node
printReverse(head.next);
// After everything else is printed
System.out.print(head.data + " ");
}
/* Inserts a new Node at front of the list. */
public void push(int new_data) {
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}
public static void main(String args[]) {
LinkedList llist = new LinkedList();
llist.push(4);
llist.push(3);
llist.push(2);
llist.push(1);
llist.printReverse(llist.head);
}
}
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.
so I have a list of basic nodes, for example nodes A B C.
each component can see what it is attached to for example:
a->b
b->c
c->a
I want a way that I can get a list of all the nodes in the graph. However, I'm running into trouble as my current system can't detect if it has already reached a point. EG in the above example it will go a->b->c->a->b etc. How can I detect this or how can I solve this problem.
My current "solution" getList() in the Node class:
ArrayList<Node> tempList = new ArrayList<Node>();
tempList.add(this);
for(int i = 0 ; i < nodesAttachedTo.size();i++){
tempList.addAll(nodesAttachedTo.get(i).getList());
}
return tempList;
You can use a HashSet. It will not allow one element to be added twice.
Here's an example code that first creates the graph similar to your example, then starts at some point in the graph and goes through it.
import java.util.HashSet;
public class Node
{
private HashSet<Node> nextNodes = new HashSet<Node>();
public Node()
{
}
public void addNextNode(Node node)
{
nextNodes.add(node);
}
public static void main(String[] args)
{
// this builds the graph of connected nodes
Node a = new Node();
Node b = new Node();
Node c = new Node();
a.addNextNode(b);
b.addNextNode(c);
c.addNextNode(a);
//this is the set that will lsit all nodes:
HashSet<Node> allNodes = new HashSet<Node>();
// this goes through the graph
a.listAllNodes(allNodes);
System.out.println(allNodes);
}
private void listAllNodes (HashSet<Node> listOfNodes)
{
// try to put all next nodes of the node into the list:
for(Node n : nextNodes)
{
if (listOfNodes.add(n)) // the set returns true if it did in fact add it.
n.listAllNodes(listOfNodes); // recursion
}
}
}
This goes from one node to all the nodes this node knows. (say that really fast three times)
Until it hits a dead end (= a node it already visited)
I chose to use a HashSet in the Node itself to store all the nodes it knows.
This could also be an ArrayList or whatever. But as I don't think there should be a connection twice, a HashSet seems to be a good choice in this situation, too.
I'm not familiar with your notation, but you could use two pointers to solve your issue. Start with two pointers that point to the same node. Increment one pointer until it returns to the start. Some pseudocode is below.
ArrayList<Node> tempList = new ArrayList<Node>();
Node head = nodesAttachedTo.get(0); //get the head of the list
tempList.add(head);
Node runner = head;
runner = runner.next;
while (!runner.equals(head)) {
tempList.add(runner);
runner = runner.next;
}
A hashmap is probably the way to go here. It allows constant time access (some overhead required, but I'm assuming you want a solution that scales well) to any element in the map.
HashMap<String, String> specificSolution = new HashMap<String, String>();
specificSolution.put("a", "b");
specificSolution.put("b", "c");
specificSolution.put("c", "a");
// To get all nodes in the graph
Set<String> nodes = specificSolution.keySet();
I implemented with String here because you don't provide a definition for the Node Class in your question, but it can be easily swapped out.
There are many different ways to represent a graph and each has their own limitations/advantages. Maybe another might be more appropriate but we would need more information about the problem.
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