Reputation: 913
Hi I have a tree in which I would like to get paths from the initial (root) node to all leaves.
I found several algortithms that list (all) apths betwenn any given two nodes within a graph (for example this SO question: Graph Algorithm To Find All Connections Between Two Arbitrary Vertices)
For binary tree there also exists an algorithm http://techieme.in/print-all-paths-in-a-tree/ but I work on a tree with various branching factors.
Is there any better way of achieving what I want to do than traversing the tree once in order to get all leaves and then run the algorithm above for all leaves combined with the initial node?
I was thinking about implementing simple DFS extended by some additional stack containing all nodes alongt he path to a single leaf and then listing all sentences by looping through these stacks.
ArrayList<GrammarNode> discovered = new ArrayList<GrammarNode>();
Stack<GrammarNode> S = new Stack<GrammarNode>();
while (!S.empty()) {
node = S.pop();
if (!discovered.contains(node)) {
discovered.add(node);
System.out.println(node.getWord.getSpelling().trim());
for (GrammarArc arc : node.getSuccessors()) {
S.push(arc.getGrammarNode());
}
}
}
UPDATE: The problem of this is that one has alyways go back to the root in order to generate full sentences. So I guess the question is: How to remember the node which was already fully visited (this means where all children nodes were already explored)?
Upvotes: 4
Views: 8162
Reputation: 1
A slight modification of DFS (which includes back-tracking) prints all the paths from a given source. In the below example the graph is represented in adjacency list format.
public void mDFS(ArrayList<node> v,int ind,ArrayList<Boolean> visit,ArrayList<node> tillNow){
visit.set(ind,true);
node n = v.get(ind);
int len = n.adj.size();
tillNow.add(n);
int count = 0;
for(node tmp: n.adj){
if( !visit.get(tmp.id) ){
count++;
tmp.pre = ind;
mDFS(v,tmp.id,visit,tillNow); // id gives index of node in v
}
}
if(count == 0){
for(node tmp: tillNow){
System.out.print((tmp.id + 1) + " - ");
}System.out.print("\n");
}
visit.set(ind,false);
tillNow.remove(tillNow.size() - 1);
return;
}
Upvotes: 0
Reputation: 7476
So here's a sample approach. Note that you need an extra visited
field in your node structure:
public class TreeNodeExtra {
int val;
TreeNodeExtra left;
TreeNodeExtra right;
boolean visited;
TreeNodeExtra (int v) {
val = v;
visited = false;
}
}
private ArrayList<ArrayList<TreeNodeExtra>> all_path_from_root_to_leaf(TreeNodeExtra root) {
Stack<TreeNodeExtra> st = new Stack<>();
ArrayList<ArrayList<TreeNodeExtra>> res = new ArrayList<>();
st.push(root);
root.visited = true;
while (!st.isEmpty()) {
TreeNodeExtra top = st.peek();
if (top.left != null && !top.left.visited) {
st.push(top.left);
top.left.visited = true;
}
// if left node is null
else {
if (top.right == null && top.left == null) {
// we have a leaf
ArrayList<TreeNodeExtra> tmpList = new ArrayList<>();
for (TreeNodeExtra t : st) {
tmpList.add(t);
}
res.add(tmpList);
st.pop();
}
else if (top.right != null && !top.right.visited) {
st.push(top.right);
top.right.visited = true;
}
else {
st.pop();
}
}
}
return res;
}
Upvotes: 0
Reputation: 88747
Printing all paths from the root to every leaf would mean to print the entire tree so I'd just use a simple DFS and do the following for each node:
Example:
A
/ \
B E
/ \ / \
C D F G
The first steps would look like this:
Upvotes: 3
Reputation: 32831
if you know that the graph is indeed a tree (there is only one path to each node), them yes, a simple DFS would be more efficient (at least from a memory usage point of view). Otherwise, you can also use the iterative deepening DFS.
Upvotes: 0