Using a function that generates a list of "adjacent" values from an input value, i.e.
Function<Object, List<?>> adjacent;
one can "traverse" any "acyclic" collection of values as a virtual graph using, for example, Depth-First Search (DFS)
in a non-recursive implementation.
public static void dfs(Object start, Function<Object, List<?>> adjacent) {
Object current;
List<?> children;
ListIterator<?> iterator;
Stack<Object> stack = new Stack<>();
stack.push(start);
while (!stack.isEmpty()) {
current = stack.pop();
System.out.println(current.toString()); // Value "visited"
children = adjacent.apply(current);
if (children == null) continue;
iterator = children.listIterator(children.size());
while (iterator.hasPrevious()) {
stack.push(iterator.previous());
}
}
}
However, if there are any "cycles" in the collection (i.e., if any "child" value has as its own child a previously "visited" member of the collection, as determined by the adjacent
function), the dfs()
method above results in an infinite loop, since it does not mark already "visited" values as such.
Assuming that there is no way to modify the adjacent
function, nor to trust the (whatever) implementation of equals()/hashCode()
for the supplied values, each of which may be a new object, can there be any way of denoting "visited" values? Wrapping them in a new object with a boolean to mark "visited" values won't work, because the adjacent
method will output generic values, not knowing whether they have been visited or not.
A simple adjacent
method to test is, for example, map::get
, with a map like
Map<Integer, List<Integer>> map = new LinkedHashMap<>();
map.put(0, Arrays.asList(1, 2));
map.put(1, Arrays.asList(3, 4));
map.put(3, Arrays.asList(1, 5));
Calling
dfs(0, map::get);
results in an infinite loop.