ConcurrentModificationError when traversing a tree recursively - java

When traversing a tree structure recursively in order to calculate weights and volumes for an entire bill of materials, I run into a ConcurrentModificationException. My approach in pseudocode:
Query initialization: add root node to list of nodes and check if it has any childs.
Progress documentation: Flag the node as visited.
Query childs: Checking for child nodes and if present add to allNodes with a level up flag.
Recursive traversal: Recursively traverse list until no more child elements are found.
I have tried to use iterators to allow myself to expand that array of nodes but ran into the same problem. Slowly running out of ideas here I am grateful for any hint.
NOTE: please forgive me to paste my problem not stating all the context for better readability. Let me know if you need more info.
// Initialization
List<Node> allNodes = new ArrayList<>();
allNodes.add(new Node(input, input, 0, false) // (1)
int counter = 0;
// Method call
getAllNodes(allNodes);
// Query parent for child elements
public void getAllNodes(List<Node> nodes){
for (Node node : nodes) {
if (!node.isVisited()) { // (2)
node.setVisited(true);
String parentId = node.getId();
Product product = QueryUtil.getFirstByIdNo(ctx, parentId, Product.class);
if (isComposite(product)) {
Iterable<Product.Row> rows = product.table().getRows(); // (3)
for (Product.Row row : rows) {
allNodes.add(new Node(parentId, row.getProductListElem().getIdno(), ++counter, false));
--counter;
}
++counter;
// Recursive query of all node elements
getAllNodes(allNodes); // (4)
}
}
}
}
//Node Bean with getters, setters, constructor, toString
#Data
class Node {
String parent;
String id;
int level;
boolean visited;
}

You are getting the error because you are trying to modify the list that you are iterating(reading) over. And this is not allowed in JAVA. [for more explanation check here]
To avoid this you can either get an iterator for your list and then loop over it, but that does not seem like a very good option for the code you have posted above. Thus, I'll recommend using List<Node> allNodes = new CopyOnWriteArrayList<>(); instead of List<Node> allNodes = new ArrayList<>().

Related

How to iterate through a list of nodes which might have sub-lists of nodes (unknown depth levels)

I have a list of nodes, and each node might have a list of subNodes (the number of levels are unknown):
class Node {
int score;
boolean selected;
List<Node> subNodes;
}
Here's how an hypothetical structure might look like:
NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
+ NODE
Combinations are just countless. I need a way to sum NODE.score for all those nodes that have NODE.selected set to true, possibly using Java 8 features. Any hints would be really appreciated.
Something like:
public int recursiveTotal(final Node node) {
//node not select, don't count the node or any of its subnodes
if (!node.selected) {
return 0;
}
//no subnodes, only node score counts
if (node.subNodes.isEmpty()) {
return node.score;
}
//node has subnodes, recursively count subnode score + parent node score
int totalScore = node.score;
for (final Node subNode : node.subNodes) {
totalScore += recursiveTotal(subNode);
}
return totalScore;
}
Coded using stackoverflow as an IDE, no guarantee against compilation errors ;)
Create a recursive method in your Node class which returns a stream of nodes concatenating a stream of the parent node and the sub nodes:
class Node {
int score;
boolean selected;
List<Node> subNodes;
public Stream<Node> streamNodes() {
return Stream.concat(Stream.of(this), subNodes.stream().flatMap(Node::streamNodes));
}
}
and use it like below to stream over your list:
List<Node> myNodes = //your list
int sum = myNodes.stream()
.flatMap(Node::streamNodes)
.filter(Node::isSelected)
.mapToInt(Node::getScore)
.sum();
TL;DR
Judging by the structure, you've provided each Node in your List is the root of an N-ary Tree data structure (I assume that there are no circles).
And in order to get the required data, we can utilize one of the classic tree-traversal algorithms. In case when the average depth is lower than the average width Depth first search algorithm would be more suitable because it would be more space-efficient, in the opposite situation it would be better to use Breadth first search. I'll go with DFS.
It's easier to come up with a recursive implementation, so I'll start with it. But it has no practical value in Java, hence we would proceed with a couple of improvements.
Streams + recursion
You can create a helper-method responsible for flattening the nodes which would be called from the stream.
List<Node> nodes = // initializing the list
long totalScore = nodes.stream()
.flatMap(node -> flatten(node).stream())
.filter(Node::isSelected)
.mapToLong(Node::getScore)
.sum();
Recursive auxiliary method:
public static List<Node> flatten(Node node) {
if (node.getSubNodes().isEmpty()) {
return List.of(node);
}
List<Node> result = new ArrayList<>();
result.add(node);
node.getSubNodes().forEach(n -> result.addAll(flatten(n)));
return result;
}
No recursion
To avoid StackOverflowError method flatten() can be implemented without recursion by polling and allocating new nodes on the stack (represented by an ArrayDeque) iterativelly.
public static List<Node> flatten(Node node) {
List<Node> result = new ArrayList<>();
Deque<Node> stack = new ArrayDeque<>();
stack.add(node);
while (!stack.isEmpty()) {
Node current = stack.poll();
result.add(current);
current.getSubNodes().forEach(stack::push);
}
return result;
}
No recursion & No intermediate data allocation
Allocating intermediate data in the form of nodes which eventually would not be used is impractical.
Instead, we can make the auxiliary method to be responsible for calculating the total score produced by summarizing the score of each selected node in the tree of nodes.
For that we need to perform isSelected() while traversing the tree.
List<Node> nodes = // initializing the list
long totalScore = nodes.stream()
.mapToLong(node -> getScore(node))
.sum();
public static long getScore(Node node) {
long total = 0;
Deque<Node> stack = new ArrayDeque<>();
stack.push(node);
while (!stack.isEmpty()) {
Node current = stack.poll();
if (current.isSelected()) total += current.getScore();
current.getSubNodes().forEach(stack::push);
}
return total;
}

How to get all paths between to items

I have to compute all possible paths between two items from a list. Each item has two fields: its name and its neighbor's name.
I have to generate a list containing all items that would allow me to make a path between two particular items.
Imagine I have Item(A, B) and Item(A, C) and I am being asked for the solution from B to C. I have to return both Items as I can reach C from B by using both of them: B->A->C.
Note that I have no limit on the Items I need to reach a destination.
I have tried several solutions but none of them was successful. I know I have to use some kind of recursive function but I can't figure out how.
This is my Item class:
public class Item {
private String name;
private String neighbor;
public Item(String name, String neighbor){
this.name = name;
this.neighbor = neighbor;
}
//getters and setters
}
As I have to obtain all possible paths between two particular items, I have to return a list of lists:
List<List<Item>> solution;
My workaround
I finally converted my items to a Graph and, once it is build, I use Depth First Transversal (DFT) in order to find all possible paths between a source and a destination.
I set key-value pairs relating each Item's name with a graph representation and, from the Graph I get a list of Integers that indicates the path in the graph (1-2-3-5, for instance). From that list I find my Items and I return a list of lists with the format I've already explained.
Posting just for someone with a similar problem!
Try something like this based on my comment:
you could iterate over each node and perform a depth-first search on
each node to see if you can reach the desired node
You mark visited nodes both to avoid cycles (if they're even possible in your use-case) and to track the path.
List<Item> depthFirstSearch(Item startItem, Item desiredItem, List<Item> visitedNodes) {
if (startItem.equals(desiredItem)) {
return visitedNodes;
}
// Exit if we reach a cycle or no more neighbors to follow
if (visitedNodes.contains(startItem) || startItem.getNeighbor() == null) {
return null;
}
visitedNodes.add(startItem);
// Recurse; continue search from neighbor
return depthFirstSearch(startItem.getNeighbor(), desiredItem, visitedNodes);
}
And use it like this (You'll need to adapt this to your code):
List<Item> items;
List<List<Item>> result = new List<List<Item>>();
for (Item item : items) {
List<Item> pathToDesired = depthFirstSearch(item, desiredItem, new LinkedList<Item>());
if (pathToDesired != null) {
results.add(pathToDesired);
}
}
result will contain all paths to the desired item.

Swap collections during iteration

I have a List of Nodes which contains nested list of child nodes. I am trying to iterate through all of them to find a particular node.Currently I start at the child nodes from the root level, then go one level deep to sub child node and so on using for-each loop.
This is my code:
List<Node> children = root.getChildren();
boolean found = false;
while (!found) {
for (Node node : children) {
if (!node.getData().toString().toUpperCase().contains("BRANCH")) {
if(condition){//some processing}
} else {
//swap children with sub children
if (children.get(0) != null) {
children = children.get(0).getChildren(); // this operation is not possible during iteration
}
}
} else {
continue;
}
}
}
}
If child node doesn't find any match, then I need to swap the collection with sub child node and continue iteration and so on.
Is there a better way to iterate through a nested nodelist of children?
Instead of swapping the collections, you could add the elements to a queue, and keep iterating till the queue is empty (i.e. you didn't find a match). Or you do find a match and return early.
public static void algorithm(Node root) {
Queue<Node> q = new LinkedList<>();
q.add(root);
while(!q.isEmpty()) {
Node current = q.poll();
if(current .getData().toString().toUpperCase().contains("BRANCH")) {
continue;
}
if(condition){
//some processing
return;
} else {
q.addAll(current.getChildren());
}
}
}
algorithm(root);
You can't swap like this mid-iteration. Remember that your for loop is translated in Java like this:
for (Iterator<Node> it = children.iterator(); it.hasNext(); ) {
Node node = it.next();
// The rest of it
}
So even if you change what children is, your iterator stays as it is.
I would suggest using a Queue to help you here.
PS Do you really want to skip all of the non-first children? That appears to be what you're currently doing.

How to get recursively get all leaves of a Tree Structure in Java

I have a Database Table of a Tree Nodes as below. I want to make a ArrayList in Java out of these Tree Nodes. the Arraylist will recursively fetch all the Tree Nodes in a Recursive Format in Java.
Input:
Database Table
Name ID Parent_ID
Parent 1
Child-1 2 1
Child-1.1 3 2
Child-1.1.1 4 3
Child-2 5 1
Child-3 6 1
Child-1.1.1.1 7 4
Child-1.2 8 2
I want to make an ArrayList of the above table in the below Java format where Sub is list of the Child Nodes, if no Child Node then Sub is Null.
public class Node {
private String id;
private String name;
private String type;
private String value;
private List<Node> sub;
}
Output:
Parent
Child-1
Child-1.1
Child-1.1.1
Child-1.1.1.1
Child-1.2
Child-2
Child-3
Can someone please help in creating a recursive function in Java to implement the above.
Recursive function:
public void printTree(Node tree,int num)
{
if(tree==null || tree.getSub()==null)return;
for(Node n : tree.getSub())
{
System.out.println(new String(new char[num]).replace("\0", " ")+"*"+n.getName());
printTree(n,num+1);
}
}
public void callRec(Node tree)
{
System.out.println(tree.getName());
printTree(tree,1);
}
The result will be:
Parent
*Child-1
*Child-1.1
*Child-1.1.1
*Child-1.1.1.1
*Child-1.2
*Child-2
*Child-3
The problem can be solved in two steps as follows, where the notation is some Java-ish pseudocode. First, all of the database rows have to be put in a List<Node> Nodes, where Node should have an additional member ParentID and the actual tree structure has to be built. This can be done as follows in time O(n^2), which is not optimal, but makes no additional assumptions on the node indices.
for (int i = 0; i < Nodes.Count(); i++) // iterate nodes
{
for (int j = 0; j < Nodec.Count(); j++) // search parent of i-th node
{
if (Nodes[j].id.Equals(Nodes[i].ParentID)) // j-th node is parent of i-th node
{
Nodes[j].sub.add(Nodes[i]); // add i-th node to children of j-th node
}
}
}
Afterwards, the leaves can be identified easily as these are the nodes which have no children.
for (int i = 0; i < Nodes.Count(); i++)
{
if (Nodes[i].sub.Count() == 0) // i-th node is a leaf
{
// do something with a leaf
}
}
Note that I am not too familiar with Java from the top of my head, but the algorithmic idea should be understandable.
Here is a rough algo:
ArrayList<Integer> ar = new ArrayList<Integer>();
public extract(node root){
foreach(node i : root.sub)
extract(i);
ar.add(i.value);
}

Insert items in ascending order in a singly linked list in Java

I need to modify the insert method of my program so that it inserts items into a singly linked list in ascending order. I understand what a linked list is but have no clue how to insert the items in order. Here are my programs so far(not the entire program):
public class SinglySortedLinkedList
{ private Node h; // list header
public SinglySortedLinkedList()
{ h = new Node(); // dummy node
h.l = null;
h.next = null;
}
public boolean insert(Listing newListing)
{ Node n = new Node();
if(n == null) // out of memory
return false;
else
{
n.next = h.next;
h.next = n;
n.l = newListing.deepCopy();
return true;
}
}
here is the tester method:
public class MainSinglyLinkedList
{ public static void main(String[] args)
{ SinglySortedLinkedList boston = new SinglySortedLinkedList();
Listing l1 = new Listing("Bill", "1st Avenue", "123 4567" );
Listing l2 = new Listing("Al", "2nd Avenue", "456 3232");
Listing l3 = new Listing("Mike", "3rd Avenue", "333 3333");
boston.insert(l1); // test insert
boston.insert(l2);
boston.insert(l3);
boston.showAll();
l3 = boston.fetch("Mike"); // test fetch of Mike
System.out.println(l3.toString());
boston .delete("Al"); // test delete of Al
boston.showAll();
boston.update("Mike", l2); // test update of Mike to Al
boston.showAll();
System.exit(0);
}
}
Any ideas of some pseudocode of how to insert in ascending order by the names would be so great, thanks
I don't want to do your homework, but I'll give you hints. If you have more specific questions then, you will probably find answers in SO. In the unlikely situation where you don't, feel free to ask a new question ;)
First, you need to find the point in the list where you want to insert, and then insert your Node n (containing the new Listing) at that point. This can be done using a while loop, with a comparison between listings as a condition, which in english would be said:
while the listing of the current node is inferior to the listing I
want to insert, I keep on going
For how to do this kind of comparison on Strings in Java, have a look at the compareTo method.
Then, use your former piece of code to insert n there. See the note below to see what I have to say about it and your dummy Node.
Side note
You're using a "dummy node" for your list header, and always insert after that one.
This is probably not necessary, you could insert each new Node in place of h and make it point to the former h, which would be both cleaner and easier to read IMHO.
Instead of:
n.next = h.next;
h.next = n;
n.l = newListing.deepCopy();
You could have:
n.next = h; // here n's next points to the former head h
h = n; // now n in the new head referenced by h
n.l = newListing.deepCopy();
This way, you don't even need a dummy node anymore, null is fine to set the n.next field. It'll also probably simplify your fetch method.

Categories

Resources