I am trying to implement Dijkstra’s algorithm in Java REST webservice, I used this link for my help.
In this link, it is creating only one graph and calculating one route successfully. But in my program, I am creating multiple graphs and using different variables as cost for each graph. Then I use ExecutorService (total threads = total number of graphs) to find all paths in parallel. My program is working fine when I call it to test paths.
The problem is, when this algorithm receives multiple requests at the same time, it is returning “Unreached” message in printPath() function for some requests, and returning correct paths for other requests successfully. I tested each path one by one, and it is returning correct path each time without any error. Problem occurs only when webservice receives multiple requests at the same time. Below is my code, I only posted classes structure which I am using, rest of the code is same as in above mentioned link.
This is how I am using ExecutorService to find path:
List<RouteFutureResult> rfutureResult = new ArrayList();
executorService = Executors.newFixedThreadPool(graphs.size());//number of threads is equal to number of graphs
for (final Graph g : graphs) {
CalcRoutes calcRoutes = new CalcRoutes(g, other_parameters);
Future<String> submit = executorService.submit(calcRoutes);
rfutureResult.add(new RouteFutureResult(submit));
}
executorService.shutdown();
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
//reading response from future object
List<String> st = new ArrayList();
for (RouteFutureResult resQuery : rfutureResult) {
String path = resQuery.getFuture().get();
st.add(path);
}
This is my CalcRoutes.java call function:
#Override
public String call() throws Exception {
List<Double> djst = new ArrayList();
g.dijkstra(s);
List<Double> st = g.printPath(d, djst);
//other processing and returning results
}
Here is the Graph class which I used from mentioned link:
class Graph {
private final Map<Double, Vertex> graph;
public class Edge {
public final double v1, v2;
public final double dist;
}
public class Vertex implements Comparable<Vertex> {
public final double name;
double gid;
public double dist = Double.MAX_VALUE;
public Vertex previous = null;
public final Map<Vertex, Double> neighbours = new HashMap<>();
private void printPath(List<Double> st) {
if (this == this.previous) {
st.add(this.name);
} else if (this.previous == null) {
System.out.printf("%s(unreached)", this.name);//this is where I am getting a problem when service receives multiple requests at same time
} else {
this.previous.printPath(st);
st.add(this.name);
}
}
}
public Graph(HashMap<Double, RouteResult> edges) {
}
public void dijkstra(double startName) {
if (!graph.containsKey(startName)) {
System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName);
return;
}
final Vertex source = graph.get(startName);
NavigableSet<Vertex> q = new TreeSet<>();
for (Vertex v : graph.values()) {
v.previous = v == source ? source : null;
v.dist = v == source ? 0 : Double.MAX_VALUE;
q.add(v);
}
dijkstra(q);
}
private void dijkstra(final NavigableSet<Vertex> q) {
Vertex u, v;
while (!q.isEmpty()) {
}
}
public List<Double> printPath(double endName, List<Double> st) {
if (!graph.containsKey(endName)) {
System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName);
}
graph.get(endName).printPath(st);
return st;
}
}
This is how I am creating multiple graphs:
Graph cost = new Graph(MRoute); //MRoute is the hashmap
graphs.add(cost);//graphs is a list containing multiple graphs
I also checked already posted questions about Dijkstra's algorithm, but I couldn't find any relevant question to my problem. Somehow, this algorithm is unable to handle multiple requests, please guide me, any help would be highly appreciated.
Related
I'm trying to implement a bfs algorithm in Java,but it doesn't work as it should be.
I've made a game map comprised of HexTile objects(custom objects,similar to matrix elements). Each HexTile includes one adjacency list containing references to the elements that it's connected to, one function that returns those elements and one function that computes the distance between two HexTiles. The bfs algorithm is excecuted in another class called unit(units are placed in HexTiles) and finds every unit available in a given range from the room(currentTile). It then creates an ArrayList with the given units.
class HexTile {
static final int MAX_NEIGHBOURS = 6;
private HexTile[] neighbours;
public HexTile[] getNeighbours() {
return this.neighbours;
}
public double distanceFromTarget(HexTile target) {
double distance = Math.sqrt(Math.pow((this.getRow() - target.getRow()), 2) + Math.pow((this.getCol() - target.getCol()), 2));
return distance;
}
}
class Unit {
private ArrayList<Unit> unitsWithinRange = new ArrayList<Unit>();
private void findUnitsWithinRange(HexTile currentTile, int attackRange) {
Queue<HexTile> queue = new LinkedList<>();
ArrayList<HexTile> visited = new ArrayList<HexTile>();
queue.add(currentTile);
visited.add(currentTile);
while (!queue.isEmpty()) {
HexTile aux = queue.poll();
for (HexTile auxNeigh : aux.getNeighbours()) {
if (auxNeigh != null && (!visited.contains(auxNeigh))) {
visited.add(auxNeigh);
queue.add(auxNeigh);
}
}
if (aux != null && (currentTile.distanceFromTarget(aux) <= attackRange)) {
Unit auxUnit = aux.getUnitOnTile();
this.unitsWithinRange.add(auxUnit);
}
}
queue.clear();
visited.clear();
}
}
What happens whenever findUnitsWithinRange is excecuted is that it return a list of units,but the units that are in range 1 are not included(direct neighbours to root).Sometimes the program crashes,because units need to be able to know if there are any nearby units,to excecute some other functions.Any advice would be appreciated!
I am not sure how to convert a function I've written so that it will run as multiple threads concurrently in Java.
The function takes a root, which will be different for each thread that "splits off" at a given junction point (the if statement for this is within the function, each newly-created thread should be able to split off in the future as well, at the next junction).
I want all threads to die once they reach the target, but the "while" loop for checking whether they've reached the end is also within the function.
Basically, I want the function to be able to run multiple times concurrently, with a modified starting point each time, and for the "original" thread to be killed off before splitting.
I also can't extend Thread because I'm already extending another class, so I'm trying to do it by implementing Runnable.
Here is the class (the parent classes work fine so I don't think I need to post them):
public class Multithreaded extends ParentClass implements Runnable {
#Override
public void run() {
executeThread(modelThreaded, new HashMap<>());
}
private final Set<Tile> VISITED = new HashSet<>();
private Grid modelThreaded; //to be able to update the root?
public Multithreaded() {
super();
}
#Override
protected int runPathfinder(Grid model, List<Tile> path) {
HashMap<Tile, Integer> tileData = new HashMap<>();
this.modelThreaded = model;
this.executeThread(model, tileData);
int cost = tileData.get(model.getTarget()) - 1;
this.statistics.setPathFound(true, cost);
this.painter.drawPath(path, model);
return cost;
}
private void executeThread(Grid model, HashMap<Tile, Integer> tileData) {
// Keeps track of visited tiles
VISITED.add(model.getRoot());
//start at the root
Tile currentTile = model.getRoot();
List<Tile> posNeighbors = model.getTileNeighbors(currentTile);
List<Tile> validNeighbors = new ArrayList<>();
int DEFAULT_DISTANCE = 1;
tileData.put(model.getRoot(), DEFAULT_DISTANCE);
int iteration = 0;
while (!isVisited(model.getTarget())) {
iteration++;
posNeighbors.clear();
validNeighbors.clear();
posNeighbors = model.getTileNeighbors(currentTile);
validNeighbors = getForward(posNeighbors);
//debugging
System.out.println("Valid Neighbors for currentTile ("
+ currentTile.getX() + ", " + currentTile.getY() + "): ");
for (Tile validNeighbor : validNeighbors) {
System.out.println(validNeighbor.getX() + ", " + validNeighbor.getY());
}
// tries to split along junctions into multithreads
// tries to kill mouse if there's a dead end
if (validNeighbors.size() > 0) {
for (Tile validNeighbor : validNeighbors) {
currentTile = validNeighbor;
// want to create a new thread for each validNeighbor here, but with
// a small change: the root changes to the current validNeighbor
model.setRoot(validNeighbor);
Runnable runnable = new Multithreaded();
Thread thread = new Thread(runnable);
thread.start();
}
}
//attempt to kill/stop current thread if there are no more options left for that thread
else {
break;
}
VISITED.add(currentTile);
tileData.put(currentTile, DEFAULT_DISTANCE + iteration);
}
private List<Tile> getForward(List<Tile> posNeighbors) {
List<Tile> validNeighbors = new ArrayList<>();
for (Tile posNeighbor : posNeighbors) {
if (posNeighbor != null && !posNeighbor.isWall()
&& !isVisited(posNeighbor)) {
validNeighbors.add(posNeighbor);
}
}
return validNeighbors;
}
private boolean isVisited(Tile posNeighbor) {
for (Tile visitedTile : VISITED) {
if (visitedTile == posNeighbor) {
return true;
}
}
return false;
}
}
As you can see, I want the threads to keep going unless:
one of them encounters the target (model.getTarget()) or
it reaches a point where there are 0 validNeighbors.
When there's 1 validNeighbor for a thread, it should stay singular and proceed along that path until it either reaches another junction or a dead end (getForward returns only the unvisited neighbors)
So, when a thread encounters a junction (2 validNeighbors), it should split into two and kill the original thread (stopping its execution of executeThread, which is why I put a break in there), with one thread for each direction, and continue running the algorithm. With my current code, it runs down the path correctly, but doesn't split into different threads and doesn't stop running when it encounters a dead end.
What would be the best way to get this to run? Am I correct in putting executeThread() in run(), or is there somewhere else I should be putting it? I've tried just doing runnable.run() instead of Thread thread and thread.start(), but that doesn't seem to help. I'm really not sure what to do here, I feel like I'm missing something obvious...
EDIT: runPathfinder is the function called by the parent classes in order for all of this code to run
I think the following mre(1) reproduces the multi-threading functionality required.
Each node (state / tile) is represented by an integer.
getTileNeighbors returns 3 random neighbors.
All thread share a synchronized visited collection, and should stop after target was added to visited.
(copy-paste the entire code to Main.java and run)
import java.util.*;
public class Main {
public static void main(String[] args) {
new Thread(new Multithreaded(0, 20)).start();
}
}
class Multithreaded implements Runnable {
// Synchronized Set (shared between threads)
private static final Set<Integer> visited = Collections.synchronizedSet(new HashSet<Integer>());
private final int root, target;
//root and target assumed >=0
public Multithreaded(int root, int target) {
this.root = root;
this.target = target;
}
#Override
public void run() {
executeThread(root);
}
private void executeThread(int root) {
visited.add(root);
System.out.println("New thread, root="+ root);
while (!isStopConditionMet()) {
List<Integer> neighbors = getTileNeighbors(root);
//todo if neighbors is empty break out of the while loop
for (Integer neighbor : neighbors) {
if(! visited.add(neighbor)) {
continue; //skip is already visited
}
Runnable runnable = new Multithreaded(neighbor, target);
Thread thread = new Thread(runnable);
thread.start();
}
}
}
//returns a list o 3 random numbers between 0-target (inclusive)
//to represent 3 random neighbors
private List<Integer> getTileNeighbors(int currentTile) {
Random rnd = new Random();
int maxValue = target +1;
return Arrays.asList(rnd.nextInt(maxValue), rnd.nextInt(maxValue), rnd.nextInt(maxValue));
}
private boolean isStopConditionMet() {
return visited.contains(target);
}
}
(1) mre should demonstrate the problem to be solved, and not a specific application.
I am trying to use JUNG's EdmondsKarpMaxFlow object to find the max flow between all node pairs in a directed graph. I created a simple directed graph and ran it on each combination of nodes with no error. Here's the working example for reference:
https://pastebin.com/TLsEduxZ
However, when I call the same 'edkAlg.evaluate()' code on a more complex graph, the loop stops on a certain edge/iteration each time.
public class SomeClass{
...
...
MyEdmondsKarpMaxFlow edk = new MyEdmondsKarpMaxFlow(dirGraph);
edk.runEdk();
}
public class MyEdmondsKarpMaxFlow {
int edgeFlowMapId = 0;
protected DirectedSparseMultigraph<GraphElements.MyVertex, GraphElements.MyEdge> dirGraph;
protected Map<GraphElements.MyEdge, Double> edgeFlowMap = new HashMap<GraphElements.MyEdge, Double>();
protected Transformer<GraphElements.MyEdge, Double> capTransformer = new Transformer<GraphElements.MyEdge, Double>() {
public Double transform(GraphElements.MyEdge edge) {
return edge.getCapacity();
}
};
// This Factory produces new edges for use by the algorithm
protected Factory<GraphElements.MyEdge> edgeFactory = new Factory<GraphElements.MyEdge>() {
public GraphElements.MyEdge create() {
return new GraphElements.MyEdge(Integer.toString(edgeFlowMapId++));
}
};
public MyEdmondsKarpMaxFlow(DirectedSparseMultigraph<GraphElements.MyVertex, GraphElements.MyEdge> dirGraph) {
this.dirGraph = dirGraph;
}
public void runEdk() {
Collection<GraphElements.MyVertex> vertexCollection = dirGraph.getVertices();
for (Iterator iterator1 = vertexCollection.iterator(); iterator1.hasNext(); ) {
GraphElements.MyVertex v1 = (GraphElements.MyVertex) iterator1.next();
Collection<GraphElements.MyVertex> vertexCollection2 = dirGraph.getVertices();
for (Iterator iterator2 = vertexCollection2.iterator(); iterator2.hasNext(); ) {
GraphElements.MyVertex v2 = (GraphElements.MyVertex) iterator2.next();
if (v1.equals(v2)) continue;
EdmondsKarpMaxFlow<GraphElements.MyVertex, GraphElements.MyEdge> edkAlg = new EdmondsKarpMaxFlow(dirGraph, v1, v2, capTransformer, edgeFlowMap, edgeFactory);
edkAlg.evaluate();
System.out.println("max edk flow between v1 and v2 is : " + edkAlg.getMaxFlow());
}
}
System.out.println("FIN");
}
}
I use custom definitions of Vertices and Edges which behave as expected but simply have more attributes than the trivial example. The code finds max flow between v1 and v2 perfectly fine up to the first 201 iterations, but gets stuck in '.evaluate()' after each time (it uses the same order of pairs each time so it is always stuck on problemNode123 -> problemNode456). Not too sure where I'm going wrong, and there isn't much help online so any pointers are appreciated!
You're not providing quite enough information to be sure, but the problem is almost certainly related to the fact that you haven't defined hashCode() and equals() for your custom node and edge objects.
Here's the gist of my code and it's function. It's a pick-where-you-go game to choose your path. For example, if you choose path a at the start, you get to choose between path d and e, and if you chose d you can move to f and g and so on.
I want to add backtracking. For instance, if I choose a in the beginning and go all the way to f, I want to be able to go back to d and have the choice between f and g again, or go all the way back to the starting point and choose b.
My initial thought was to use something to tell the code to go back to a certain line of code when I need to backtrack, but there's no goto in java to my understanding. I have an inkling to use loops. (I'm thinking while loops in particular.) I cannot figure out HOW to structure the loops to backtrack.
Here's my code:
public class PathGame {
public static void main (String[] args) {
String name = JOptionPane.showInputDialog("Hello! Welcome to my paths! What is your name, adventurer?");
JOptionPane.showMessageDialog(null, "Well then " + name + ", here's how this works...some generic instructions");
String startingChoice = JOptionPane.showInputDialog("Choose your path, a, b, or c.");
if (startingChoice.equals("a")){
String aChoice = JOptionPane.showInputDialog("Choose path d or path e");
if (aChoice.equals("d")) {
String dExamineChoice = JOptionPane.showInputDialog("path f or g?");
if (dExamineChoice.equals("f")) {
JOptionPane.showMessageDialog(null, name + "...!");
}
else if (dExamineChoice.equals("g")) {
JOptionPane.showMessageDialog(null, "Stuff g");
}
}
else if (aChoice.equals("e")) {
JOptionPane.showMessageDialog(null, "Stuff e");
}
else if (aChoice.equals("goBack")) {
///Backtrack back to start
}
}
else if (startingChoice.equals("b")) {
String bChoice = JOptionPane.showInputDialog("Path h or i?");
if (bChoice.equals("h")) {
String hChoice = JOptionPane.showInputDialog("Path j, k, or l?");
if (hChoice.equals("j")) {
String jExamine = JOptionPane.showInputDialog("m or n?");
if (jExamine.equals("m")) {
JOptionPane.showMessageDialog(null,"Stuff m");
}
else if (jExamine.equals("n")) {
JOptionPane.showMessageDialog(null,"Stuff n");
}
}
else if (hChoice.equals("k")) {
JOptionPane.showMessageDialog(null,"Stuff k");
}
else if (hChoice.equals("l")) {
JOptionPane.showMessageDialog(null,"Stuff l");
}
}
else if (bChoice.equals("i")) {
JOptionPane.showMessageDialog(null,"Stuff i");
}
}
}
}
Backtracking can be achieved with recursion. However, since you wanted the iterative approach. You can apply the same concept using a stack. Every time you visit a new square, push the current state into the stack. When you need to backtrack (for example you are in a dead end), pop out from the stack.
If your intention is to create something like a maze runner, you may want to record the visited squares.
And yes, you should be using a while-loop to do that.
Make an option back for each starting choice, such that when the user selects that option startingChoice is set to the letter you want to go back to.
There are two ways you could do this.
The extendable way would be to use a graph data structure. You could use something like JGraphT or TinkerPop. But that's assuming you want something really fancy. A graph would let you treat the whole path selection (traversal) very generically. It would let you design all sorts of paths and backtracking would simply be keeping track of where you came from.
The faster way would be to use a Stack data structure. Everytime you make a choice add that choice to your stack. So your current position is always stored at the top of the stack. When you backtrack just pop off the top of the stack and try again. For example:
public static void main(String []){
Stack<String> myPath = new Stack<>();
while(detinationNotReached){
myPath = goSomewhere(myPath);
}
}
public Stack goSomewhere(Stack<String> myPath){
String currentPosition = myPath.peek();
String choice = getChoice(currentPosition);
switch(choice){
case "a":
myPath.push("a");
break;
... //Other choices
case "back":
myPath.pop(); // This effectively backtracks.
break;
}
return myPath
}
Here's an example of how you store your possibilities in a graph data structure (i.e. a half-edge data structure):
class Edge {
public final Node end;
public Edge(Node end) { this.end = end; }
}
class Node {
public final int id;
public final List<Edge> edges;
public Node(int id, List<Edge> edges) { this.id = id; this.edges = Collections.unmodifiableList(edges); }
}
class Graph {
private final ArrayList<ArrayList<Edge>> halfEdges = new ArrayList<>();
private final ArrayList<Node> nodes = new ArrayList<>();
public Node addNode() {
ArrayList<Edge> edges = new ArrayList<>();
Node node = new Node(nodes.size(), edges);
halfEdges.add(edges);
nodes.add(node);
return node;
}
public Edge addEdge(Node from, Node to) {
assert nodes.contains(from) && nodes.contains(to);
Edge edge = new Edge(to);
halfEdges.get(from.id).add(edge);
return edge;
}
}
You'd use it like this:
class Game
{
public static void main (String[] args)
{
Graph graph = new Graph();
Node root = graph.addNode();
Node a = graph.addNode();
graph.addEdge(root, a);
Node b = graph.addNode();
graph.addEdge(root, b);
Node c = graph.addNode();
graph.addEdge(root, c);
Node d = graph.addNode();
graph.addEdge(a, d);
Node e = graph.addNode();
graph.addEdge(a, e);
// ...
// main loop
ArrayList<Node> path = new ArrayList<>();
StringBuilder builder = new StringBuilder();
while(true) {
if(path.isEmpty())
path.add(root);
Node pos = path.get(path.size() - 1);
builder.setLength(0);
builder.append("At ").append(pos.id).append(", choices: back");
for(Edge out : pos.edges)
builder.append(", ").append(out.end.id);
System.out.println(builder.toString());
// handle input: add chosen node to path or remove last entry if "back"
// ...
}
}
}
You can add any kind of data to a Node or an Edge, like an actual name for the choice to display (instead of id) etc...
I have a graph class with Node's, where each Node can connect to others:
public class Node {
List<Node> connections;
}
I would like to make a deep copy of the entire graph. As a first attempt, I tried making a copy constructor like:
public Node(Node other) {
connections = new ArrayList<Node>();
for (Node n : other.connections) {
connections.add(new Node(n));
}
}
So deep copying a graph would just be:
public Graph deepCopy () {
Graph g = new Graph();
g.nodes = new ArrayList<Node>();
for (Node n : nodes) {
g.nodes.add(new Node(n));
}
}
But that doesn't work as that destroys the connection relationship among the nodes. I am wondering if anyone has suggestions to do this in a simple way? Thanks.
The problem is that you need to copy the identities of the nodes, not just their values. Specifically, when you're copying some node, you need to deal with the identities of the nodes it refers to; that means that a copy constructor, or some other kind of purely local copying mechanism, can't do the job, because it only deals with one node at a time. I'm not sure that makes any sense, but I've typed it and my backspace key doesn't work.
Anyway, what you can do is pass around some other object which can tell which new node corresponds to which old node. If you wanted to be fancy (and who doesn't?) you could refer to this as a graph isomorphism. This can be something as simple as a map. As in this completely untested code:
// in Graph
public Graph deepCopy () {
Graph g = new Graph();
g.nodes = new ArrayList<Node>();
Map<Node, Node> isomorphism = new IdentityHashMap<Node, Node>();
for (Node n : nodes) {
g.nodes.add(n.deepCopy(isomorphism));
}
return g;
}
// in Node
public Node deepCopy(Map<Node, Node> isomorphism) {
Node copy = isomorphism.get(this);
if (copy == null) {
copy = new Node();
isomorphism.put(this, copy);
for (Node connection: connections) {
copy.connections.add(connection.deepCopy(isomorphism));
}
}
return copy;
}
Sergii mentions using serialization; serialization actually does something pretty similar when it traverses an object graph.
Yep, deep copy in java ( not only in java) can be made using memory serialization/deserialization
like this
public static Object copy(Object orig) {
Object obj = null;
try {
// Write the object out to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(orig);
out.flush();
out.close();
// Make an input stream from the byte array and read
// a copy of the object back in.
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(bos.toByteArray()));
obj = in.readObject();
}
catch(IOException e) {
e.printStackTrace();
}
catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
return obj;
}
Kinda late input. But I had a similar problem but came to a different solution. But not shure if its bulletproof. So please feel free to comment so I can learn!
I have a Type called "Numbers" because I have no creativity naming stuff.
Each object of type "Numbers" has an internal list that can carry additional objects of type "Numbers" of which each has a list of additional "Numbers" of which each... and so on.
Basicaly you can make a tree structure similar to this:
I solved the deep copy problem by using a recursive copy-constructor inside the "Numbers" class.
Numbers class:
import java.util.ArrayList;
public class Numbers {
private ArrayList<Numbers> numbers = new ArrayList<>();
private int number;
public Numbers(int number) {
this.number = number;
}
public Numbers(Numbers numToCopy) {
this.number = numToCopy.getNumber();
ArrayList<Numbers> list = numToCopy.getNumbers();
for(int i = 0; i < list.size(); i++) {
Numbers n = new Numbers(list.get(i));
numbers.add(n);
}
}
public void addNumber(Numbers i) {
numbers.add(i);
}
public ArrayList<Numbers> getNumbers() {
return numbers;
}
public void setNumber(int i) {
this.number = i;
}
public int getNumber() {
return number;
}
public ArrayList<Numbers> getAllNumbers(ArrayList<Numbers> list) {
int size = numbers.size();
list.addAll(numbers);
for(int i = 0; i < size; i++) {
numbers.get(i).getAllNumbers(list);
}
return list;
}
}
Usage:
import java.util.ArrayList;
public class NumbersTest {
public NumbersTest() {
}
public static void main(String[] args) {
Numbers num0 = new Numbers(0);
Numbers num1 = new Numbers(1);
Numbers num2 = new Numbers(2);
Numbers num3 = new Numbers(3);
Numbers num4 = new Numbers(4);
Numbers num5 = new Numbers(5);
Numbers num6 = new Numbers(6);
num0.addNumber(num1);
num0.addNumber(num2);
num1.addNumber(num3);
num1.addNumber(num4);
num2.addNumber(num5);
num2.addNumber(num6);
num4.addNumber(num6);
//Deep copy here!
Numbers numCopy = new Numbers(num0);
//Change deep down in graph of original
num0.getNumbers().get(0).getNumbers().get(1).getNumbers().get(0).setNumber(799);
//Printout of copy to show it was NOT affected by change in original.
for(Numbers n : numCopy.getAllNumbers(new ArrayList<Numbers>())) {
System.out.println(n.getNumber());
}
}
}
Usage code shows that changing deep inside the "graph" of the original num0 object, does not change the copy made of it.
Theres two sixes (6) in the graph, and thats ok since they are on different branches.
Downside is if same number would repeat through one of the paths, like if there was a (1) somewhere under the first 1. It would then end up in an infinite loop.
Please do comment! :)