Directed Graph Traversal - All paths - graph
Given a directed graph with
A root node
Some leaves nodes
Multiple nodes can be connected to the same node
Cycles can exist
We need to print all the paths from the root node to all the leaves nodes. This is the closest question I got to this problem
Find all paths between two graph nodes
If you actually care about ordering your paths from shortest path to longest path then it would be far better to use a modified A* or Dijkstra Algorithm. With a slight modification the algorithm will return as many of the possible paths as you want in order of shortest path first. So if what you really want are all possible paths ordered from shortest to longest then this is the way to go. The code I suggested above would be much slower than it needs to be if you care about ordering from shortest to longest, not to mention would take up more space then you'd want in order to store every possible path at once.
If you want an A* based implementation capable of returning all paths ordered from the shortest to the longest, the following will accomplish that. It has several advantages. First off it is efficient at sorting from shortest to longest. Also it computes each additional path only when needed, so if you stop early because you dont need every single path you save some processing time. It also reuses data for subsequent paths each time it calculates the next path so it is more efficient. Finally if you find some desired path you can abort early saving some computation time. Overall this should be the most efficient algorithm if you care about sorting by path length.
import java.util.*;
public class AstarSearch {
private final Map<Integer, Set<Neighbor>> adjacency;
private final int destination;
private final NavigableSet<Step> pending = new TreeSet<>();
public AstarSearch(Map<Integer, Set<Neighbor>> adjacency, int source, int destination) {
this.adjacency = adjacency;
this.destination = destination;
this.pending.add(new Step(source, null, 0));
}
public List<Integer> nextShortestPath() {
Step current = this.pending.pollFirst();
while( current != null) {
if( current.getId() == this.destination )
return current.generatePath();
for (Neighbor neighbor : this.adjacency.get(current.id)) {
if(!current.seen(neighbor.getId())) {
final Step nextStep = new Step(neighbor.getId(), current, current.cost + neighbor.cost + predictCost(neighbor.id, this.destination));
this.pending.add(nextStep);
}
}
current = this.pending.pollFirst();
}
return null;
}
protected int predictCost(int source, int destination) {
return 0; //Behaves identical to Dijkstra's algorithm, override to make it A*
}
private static class Step implements Comparable<Step> {
final int id;
final Step parent;
final int cost;
public Step(int id, Step parent, int cost) {
this.id = id;
this.parent = parent;
this.cost = cost;
}
public int getId() {
return id;
}
public Step getParent() {
return parent;
}
public int getCost() {
return cost;
}
public boolean seen(int node) {
if(this.id == node)
return true;
else if(parent == null)
return false;
else
return this.parent.seen(node);
}
public List<Integer> generatePath() {
final List<Integer> path;
if(this.parent != null)
path = this.parent.generatePath();
else
path = new ArrayList<>();
path.add(this.id);
return path;
}
#Override
public int compareTo(Step step) {
if(step == null)
return 1;
if( this.cost != step.cost)
return Integer.compare(this.cost, step.cost);
if( this.id != step.id )
return Integer.compare(this.id, step.id);
if( this.parent != null )
this.parent.compareTo(step.parent);
if(step.parent == null)
return 0;
return -1;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Step step = (Step) o;
return id == step.id &&
cost == step.cost &&
Objects.equals(parent, step.parent);
}
#Override
public int hashCode() {
return Objects.hash(id, parent, cost);
}
}
/*******************************************************
* Everything below here just sets up your adjacency *
* It will just be helpful for you to be able to test *
* It isnt part of the actual A* search algorithm *
********************************************************/
private static class Neighbor {
final int id;
final int cost;
public Neighbor(int id, int cost) {
this.id = id;
this.cost = cost;
}
public int getId() {
return id;
}
public int getCost() {
return cost;
}
}
public static void main(String[] args) {
final Map<Integer, Set<Neighbor>> adjacency = createAdjacency();
final AstarSearch search = new AstarSearch(adjacency, 1, 4);
System.out.println("printing all paths from shortest to longest...");
List<Integer> path = search.nextShortestPath();
while(path != null) {
System.out.println(path);
path = search.nextShortestPath();
}
}
private static Map<Integer, Set<Neighbor>> createAdjacency() {
final Map<Integer, Set<Neighbor>> adjacency = new HashMap<>();
//This sets up the adjacencies. In this case all adjacencies have a cost of 1, but they dont need to.
addAdjacency(adjacency, 1,2,1,5,1); //{1 | 2,5}
addAdjacency(adjacency, 2,1,1,3,1,4,1,5,1); //{2 | 1,3,4,5}
addAdjacency(adjacency, 3,2,1,5,1); //{3 | 2,5}
addAdjacency(adjacency, 4,2,1); //{4 | 2}
addAdjacency(adjacency, 5,1,1,2,1,3,1); //{5 | 1,2,3}
return Collections.unmodifiableMap(adjacency);
}
private static void addAdjacency(Map<Integer, Set<Neighbor>> adjacency, int source, Integer... dests) {
if( dests.length % 2 != 0)
throw new IllegalArgumentException("dests must have an equal number of arguments, each pair is the id and cost for that traversal");
final Set<Neighbor> destinations = new HashSet<>();
for(int i = 0; i < dests.length; i+=2)
destinations.add(new Neighbor(dests[i], dests[i+1]));
adjacency.put(source, Collections.unmodifiableSet(destinations));
}
}
The output from the above code is the following:
[1, 2, 4]
[1, 5, 2, 4]
[1, 5, 3, 2, 4]
Notice that each time you call nextShortestPath() it generates the next shortest path for you on demand. It only calculates the extra steps needed and doesnt traverse any old paths twice. Moreover if you decide you dont need all the paths and end execution early you've saved yourself considerable computation time. You only compute up to the number of paths you need and no more.
Finally it should be noted that the A* and Dijkstra algorithms do have some minor limitations, though I dont think it would effect you. Namely it will not work right on a graph that has negative weights.
Here is a link to JDoodle where you can run the code yourself in the browser and see it working. You can also change around the graph to show it works on other graphs as well: http://jdoodle.com/a/ukx
Related
Breadth first traversal of arbitrary graph with minimal memory
I have an enormous directed graph I need to traverse in search for the shortest path to a specific node from a given starting point. The graph in question does not exist explicitly; the child nodes are determined algorithmically from the parent nodes. (To give an illustration: imagine a graph of chess positions. Each node is a chess position and its children are all the legal moves from that position.) So I have a queue for open nodes, and every time I process the next node in the queue I enqueue all of its children. But since the graph can have cycles I also need to maintain a hashset of all visited nodes so I can check if I have visited one before. This works okay, but since this graph is so large, I run into memory problems. All of the nodes in the queue are also stored in the hashset, which tends to be around 50% of the total number or visited nodes in practice in my case. Is there some magical way to get rid of this redundancy while keeping the speed of the hashset? (Obviously, I could get rid of the redundancy by NOT hashing and just doing a linear search, but that is out of the question.)
I solved it by writing a class that stores the keys in a list and stores the indices of the keys in a hashtable. The next node "in the queue" is always the the next node in the list until you find what you're looking for or you've traversed the entire graph. class IndexMap<T> { private List<T> values; private LinkedList<int>[] buckets; public int Count { get; private set; } = 0; public IndexMap(int capacity) { values = new List<T>(capacity); buckets = new LinkedList<int>[NextPowerOfTwo(capacity)]; for (int i = 0; i < buckets.Length; ++i) buckets[i] = new LinkedList<int>(); } public void Add(T item) //assumes item is not yet in map { if (Count == buckets.Length) ReHash(); int bucketIndex = item.GetHashCode() & (buckets.Length - 1); buckets[bucketIndex].AddFirst(Count++); values.Add(item); } public bool Contains(T item) { int bucketIndex = item.GetHashCode() & (buckets.Length - 1); foreach(int i in buckets[bucketIndex]) { if (values[i].Equals(item)) return true; } return false; } public T this[int index] { get => values[index]; } private void ReHash() { LinkedList<int>[] newBuckets = new LinkedList<int>[2 * buckets.Length]; for (int i = 0; i < newBuckets.Length; ++i) newBuckets[i] = new LinkedList<int>(); for (int i = 0; i < buckets.Length; ++i) { foreach (int index in buckets[i]) { int bucketIndex = values[index].GetHashCode() & (newBuckets.Length - 1); newBuckets[bucketIndex].AddFirst(index); } buckets[i] = null; } buckets = newBuckets; } private int NextPowerOfTwo(int n) { if ((n & n-1) == 0) return n; int output = 0; while (n > output) { output <<= 1; } return output; } } The old method of maintaining both an array of the open nodes and a hashtable of the visited nodes needed n*(1+a)*size(T) space, where a is the ratio of nodes_in_the_queue over total_nodes_found and size(T) is the size of a node. This method needs n*(size(T) + size(int)). If your nodes are significantly larger than an int, this can save a lot.
convert a recursive algorithm into a non-recursive implementation
public void selectString(List<List<String>> candidateList, List<String> selected, List<List<String>> results, int target) { if (CollectionUtils.isEmpty(candidateList)){ return; } List<String> candidate = candidateList.get(0); for (String oneCandidate : candidate){ if (selected.contains(oneCandidate)) continue; List<String> currentSelected = new ArrayList<>(); currentSelected.addAll(selected); currentSelected.add(oneCandidate); if (currentSelected.size() >= target){ results.add(currentSelected); } this.selectString(candidateList.subList(1, candidateList.size()), currentSelected, results, target); } return; } The above code is a permutations recursive algorithm I wrote,candidateList represents the source list,selected is an empty list at the beginning,results represent the final results,target represents the size of candidateList.How can I convert my permutations recursive algorithm into a non-recursive implementation?
Recursive method to get the number of occurences of an element in a binary tree
Hi. I am having trouble writing this method (in the photo) in a recursuve format. The method gets the amount of occurences of a given element in the binary search tree. To solve this recursively, I was trying to implement it with a private helper method of the same name, like this: public int count(){ count = 0; if (root == null) return count; return count (root.getInfo()); private int count(T element){ (Basically the same code you see in the photo) } but I ended up with overflow errors. Would you mind taking a look and telling me how I can structure this method recursively? Cheers, and thanks.
A tentative implementation may looks like this. public int count(T element, T root){ if(element == null) { return 0; } int count = 0; int compare = element.compareTo(root.getInfo()); if(compare == 0){ count++; } count += count(element, root.getLeft()); count += count(element, root.getRight()); return count; } count(item, root);
Binary Tree and Return root node
..I'm building a binary tree where the root is given and the children are either root-3, root-2 or root-1 (that is, they hold those number of pennies). So 5 would have nodes of 2,3,4, and so on, until the leaves are 0. Here's my method for making such a tree. I don't understand why the method doesn't return the original node, in this case, the value should be 3. Any guidance would be awesome. public GameNode buildTree1(GameNode root){ int penn = root.getPennies(); if (penn < 0) { return null; } else { root.print(); root.setLeft(buildTree1(new GameNode(penn-1))); root.setMiddle(buildTree1(new GameNode(penn-2))); root.setRight(buildTree1(new GameNode(penn-3))); return root; } Get/Set Methods public void setLeft(GameNode newNode) { // TODO Auto-generated method stub left = newNode; } Same for setMiddle and setRight;
Lucene number of occurrences
I am using Lucene.net in my Web App. Everithing works fine, but now i have to show the number of occurrences of my 'searchstring' in every single document of the hits array. How can i do this? I use usual BooleanQuery. That is my search: BooleanQuery bq = new BooleanQuery(); bq.Add(QueryParser.Parse(Lquery, "", CurIndexDescritor.GetLangAnalizer()), false,false); BooleanQuery.SetMaxClauseCount(int.MaxValue); IndexSearcher searcher = new IndexSearcher(indexPath); Hits hits = (filter != null) ? searcher.Search(bq, filter) : searcher.Search(bq); for (int i = 0; i < hits.Length(); i++) { Document doc = hits.Doc(i); SearchResultItem MyDb = new SearchResultItem(); MyDb.key = doc.Get(KeyField); MyDb.score = hits.Score(i); result.Add(MyDb); } Where can i get the number of occurrences? Thanks!
If you dont want the score back and dont want to order the results using score you could probably build a custom Similarity implementation. I quickly tested the following code, and it appears to work fine with TermQueries and PhraseQueries, i didnt test more query types tho. A PhraseQuery hit counts as a single occurence. public class OccurenceSimilarity : DefaultSimilarity { public override float Tf(float freq) { return freq; } public override float Idf(int docFreq, int numDocs) { return 1; } public override float Coord(int overlap, int maxOverlap) { return 1; } public override float QueryNorm(float sumOfSquaredWeights) { return 1; } public override Explanation.IDFExplanation idfExplain(System.Collections.ICollection terms, Searcher searcher) { return CACHED_IDF_EXPLAIN; } public override Explanation.IDFExplanation IdfExplain(Term term, Searcher searcher) { return CACHED_IDF_EXPLAIN; } public override float SloppyFreq(int distance) { return 1; } private static Explanation.IDFExplanation CACHED_IDF_EXPLAIN = new ExplainIt(); private class ExplainIt : Explanation.IDFExplanation { public override string Explain() { return "1"; } public override float GetIdf() { return 1.0f; } } } To use it: Similarity.SetDefault(new OccurenceSimilarity());