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)?
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:
add it to the list/stack
if the node has children, repeat for the children
if the node is a leaf, print the list/stack
pop the node from the list/stack
Example:
A
/ \
B E
/ \ / \
C D F G
The first steps would look like this:
put A on the list -> {A}
put B on the list -> {A,B}
put C on the list -> {A,B,C}
since C is a leaf, print the list (A,B,C)
remove C from the list -> {A,B}
put D on the list -> {A,B,D}
since D is a leaf, print the list (A,B,D)
...
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.
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;
}
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;
}
Related
I implemented public BinarySearchTree<Node,T> chop(T x)
that chops my tree into two parts at element x. The SSet this will contain elements < x, and the returned SSet is a SSet that contains elements >= x. This should work for all elements regardless of whether they are in this.
For example, suppose s={2,4,6,8}. Then s.chop(3) returns {4,6,8} and s becomes {2}. We would get the same result for s.chop(4).
The slowChop method is implemented, but it has a time complexity of O(n), but I need to reduce it to at least O(h) when the tree is balanced (where h is the height of the tree).
public BinarySearchTree<Node,T> slowChop(T x) {
Node sample = super.newNode();
BinarySearchTree<Node,T> other = new
BinarySearchTree<Node, T>(sample);
// Iterate through the n nodes in-order.
// When see value >=x, add to new BST in O(height) time, and
// remove it from this BST (on next iteration) in O(height) time.
Iterator<T> it = iterator();
T prev = null;
while( it.hasNext() ) {
T curr = (T)(it.next());
if( c.compare(curr, x) >= 0 ) { // we have our first >= x
other.add(curr);
if( prev != null ) {
this.remove(prev); // safe to remove now
}
prev = curr;
}
}
if( prev != null ) {
this.remove(prev); // edge case, get that last one!
}
return other;
}
public BinarySearchTree<Node,T> chop(T x) {
Node sample = super.newNode();
BinarySearchTree<Node,T> other = new
BinarySearchTree<Node, T>(sample);
// TODO: Implement this method. It should match slowChop in
// behaviour, but should be faster :-)
return other;
}
Indeed, your algorithm is not making use of the efficiency that you can get from the fact you are dealing with a binary search tree. So iterating through the tree with an in-order traversal is not the way to go.
Instead, perform a binary search and cut the edges that link two nodes which should end up in different trees. While cutting you'll also need to reattach nodes to where a previous cut was performed. The complexity is the same as a binary search towards the bottom of the tree, and so it is O(logn).
Here is an implementation that assumes you have the regular getters and setters:
on the Node class: getLeft, setLeft, getRight, setRight, getValue, and
on the BinarySearchTree class: getRoot, setRoot
public BinarySearchTree<Node,T> chop(T x) {
// Create two temporary dummy (sentinel) nodes to ease the process.
Node rightRootParent = super.newNode();
Node leftRootParent = super.newNode();
// Set "cursors" at both sides
Node rightParent = rightRootParent;
Node leftParent = leftRootParent;
// Start the binary search for x, cutting edges as we walk down
Node node = this.getRoot();
while (node != null) {
// Decide for each node in the binary search path at which side it should go
if (c.compare(node.getValue(), x) >= 0) {
// Node should belong to the right-side tree
rightParent.setLeft(node); // Establish edge
rightParent = node;
node = node.getLeft(); // Move down
rightParent.setLeft(null); // Cut next edge for now (it might get restored)
} else { // Symmetric case
leftParent.setRight(node);
leftParent = node;
node = node.getRight();
leftParent.setRight(null);
}
}
// Set the roots of both trees
this.setRoot(leftRootParent.getRight());
return BinarySearchTree<Node, T>(rightRootParent.getLeft());
}
I have implemented BinarySearchTree.slowChop, but need to implement faster algorithm.
Definition:
public BinarySearchTree<Node,T> chop(T x)
that chops our sorted set into two parts at element x. The SSet this contains elements < x, and the returned SSet is a SSet that contains elements >= x. This should work for all elements regardless of whether they are in this.
For example, suppose s={2,4,6,8}. Then s.chop(3) returns {4,6,8} and s becomes {2}. We would get the same result for s.chop(4).
slowChop method is implemented but take O(n) time, need to reduce it to at least O(h) if tree is balanced.
public BinarySearchTree<Node,T> slowChop(T x) {
Node sample = super.newNode();
BinarySearchTree<Node,T> other = new
BinarySearchTree<Node, T>(sample);
// Iterate through the n nodes in-order.
// When see value >=x, add to new BST in O(height) time, and
// remove it from this BST (on next iteration) in O(height) time.
Iterator<T> it = iterator();
T prev = null;
while( it.hasNext() ) {
T curr = (T)(it.next());
if( c.compare(curr, x) >= 0 ) { // we have our first >= x
other.add(curr);
if( prev != null ) {
this.remove(prev); // safe to remove now
}
prev = curr;
}
}
if( prev != null ) {
this.remove(prev); // edge case, get that last one!
}
return other;
}
Following drive link contains the helper classes: BinarySearchTree BinaryTree DefaultComparator SSet
https://drive.google.com/drive/folders/1Uc6pNFg8e3WyeiinVFk6yA4W0LdB6UGx?usp=sharing
I see similar solution is available in All Possible paths K edges far
. But I am looking for experts guidance - how to solve each of the
following constraints over the common question :
a)It should be a clever BFS solution
b)The signature should be at least **printAllGraphPaths( Node source, Node target,....)** [not integer]
c)Source and target should be internal nodes [not like source having zero in-degree and target with zero out-degree]
d)Nodes though can be different instances but can have same value`
e)Result can't be more than K edges.
f)Same node can be visited multiple times (eg. Node(2) )
g)Can have cycles
Given source = 1 & target = 3, then printAllPossiblePaths :
1 -> 2 -> 3
1 -> 5 -> 3
1 -> 5 -> 2 -> 3
1 -> 6 -> 5 -> 2 -> 3
1 -> 6 -> 5 -> 3
for duplicate node 5 there will be three more extra paths
1 -> 5 -> 2 -> 5 -> 3
1 -> 2 -> 5 -> 3
1 -> 6 -> 5 -> 2 -> 5 -> 3
Follow-up additional Question:
What is better DFS or BFS in which situation and why ?
I will outline a clever solution for you, but not implement it.
The goal is to be able to print paths but not waste time in enumerating paths that don't want up in the right place. So you want a data structure that looks like this:
by node
by length of remaining path
list of nodes you could go to to get to the desired target.
No matter how many paths there are, this data structure is polynomial in size and can be generated in polynomial time using standard dynamic programming techniques starting with the target (not the source). This will be a breadth-first algorithm.
Now you take your source node and k. And using this data structure you can do a depth-first search through the data structure, printing paths as you go. This will take time proportional to how much data you are printing. But you will never be going down a wrong turn and exploring paths that do not work.
Bonus optimization. The algorithm that I described will work. But for the special case of very large graphs and very short k (think "path from person A to person B in a large social network") it can be improved substantially. The improvement is to start from the target and go back ceil(k/2) and start from the source and (by reversing the path structure) and go forward floor(k/2). Store the fringe of both in a hash structure. And now we walk through the intersection of the fringes, and construct the paths in both directions.
This optimization can always be done. But won't be an improvement except in the one special case.
To see why it is an improvement, suppose that you have 50 average connections per person and you are trying to find a path of length 6 from you to the President. The first version that I described basically winds up having to construct a data structure the size of the whole social graph. Which is quite literally billions of things. But with the bonus optimization you draw a circle whose size is in the hundreds of thousands from you, and another of the same size from the President then intersect them. The preprocessing step therefore takes less than a million operations. Which is much better than billions!
I have successfully created my solution code!
Feel free to discuss and suggest to improve its complexity (time & space) or some better approach. People might find its over engineered but my point was...in real life who inputs two ints as src and dest ? I needed solid Nodes too:
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Queue;
public class AllPathsAdhocSrcDestNodes{
List<List<Integer>> allPaths = new ArrayList<>();
public List<List<Integer>> bfs(Graph g, Node src,Node dest,int m){
int depth =0; List<Integer> tempPath = null;
Queue<Node> q = new ArrayDeque<>();
src.path.add(src.value);
q.add(src);
while(!q.isEmpty()){
Node u = q.poll();
depth = u.depth;
if (depth > m)
continue;
if(u.value == dest.value && depth <= m){
allPaths.add(u.path);
}
List<Node> neighbours = g.adjMap.get(u);
for(int k=0;k<neighbours.size();k++){
Node v = neighbours.get(k);
tempPath = new ArrayList<>(u.path);
tempPath.add(v.value);
q.add(new Node(v.value,u.depth+1,tempPath));
}
}
return allPaths;
}
/*------------------------ Driver program ---------------------------------*/
public static void main(String[] args){
// List of graph nodes & edges as per diagram
Node[] n = { new Node(0),new Node(1),new Node(2),new Node(3),new Node(4),new Node(5),new Node(6),new Node(7) };
Edge[] e = {
new Edge(n[0], n[6]),
new Edge(n[0], n[1]),
new Edge(n[1], n[6]),
new Edge(n[1], n[5]),
new Edge(n[1], n[2]),
new Edge(n[2], n[3]),
new Edge(n[3], n[4]),
new Edge(n[5], n[2]),
new Edge(n[5], n[3]),
new Edge(n[5], n[4]),
new Edge(n[6], n[5]),
new Edge(n[7], n[6]),
new Edge(n[7], n[1])
};
// construct graph : Graph acc to CLRS is G(V,E) nothing else
Graph g = new Graph(Arrays.asList(n),Arrays.asList(e));
//inputs
Node src = n[1], dest = n[3];
int m = 4;
// Do modified BFS traversal from source vertex src
AllPathsAdhocSrcDestNodes tester = new AllPathsAdhocSrcDestNodes();
System.out.println(tester.bfs(g, src, dest,m));
}
public static void printQ(Queue<Node> q,int k){
System.out.println(k+"queue:"+q);
}
}
class Edge{
Node source, dest;
public Edge(Node source, Node dest) {
this.source = source;
this.dest = dest;
}
}
class Graph{
List<Node> vertices;
List<Edge> edges;
HashMap<Node,List<Node>> adjMap = null;
Graph(List<Node> vertices,List<Edge> edges)
{
this.vertices=vertices;
this.edges=edges;
int N = vertices.size();
adjMap = new HashMap<>(N);
for (int i = 0; i < N; i++) {
adjMap.put(vertices.get(i), new ArrayList<>());
}
// add edges to the directed graph
for (int i = 0; i < edges.size(); i++){
Node src = edges.get(i).source;
Node dest = edges.get(i).dest;
adjMap.get(src).add(dest);
}
}
}
class Node{
int value;
int depth;
List<Integer> path = new ArrayList<>(); //path from root till this node just for printing we dont need List<Node>
public Node(int value) {
this.value = value;
}
public Node(int value,int depth,List<Integer> tempPath) {
this.value = value;
this.depth = depth;
this.path = tempPath;
}
#Override
public boolean equals(Object obj){
if(obj == null || !(getClass()==obj.getClass()) || this.value != ((Node)obj).value )
return false;
else
return true;
}
#Override
public int hashCode(){
return this.value;
}
public String toString() {
return String.valueOf(value);
}
}
Drop a comment if you liked my effort
So I'm building this tree which has 1..* Nodes where each node has a list which in themselves can have 1..* nodes.
The first three levels of the tree I can build just fine but then it won't work more if I don't code all the levels which are just plain stupid. The solution is of course to use some kind of recursive method and a BFS.
Basically, in my TreeBuilder class, I want to be able to call tree.getNodesAtDepth(depth)) and get a list of all nodes that are at that depth. Problem is that I don't understand how I can implement the getNodesAtDepth(depth) method.
All the examples I find are for binary trees. An alternative is to have the addChild method take a depth argument so I can specify at which depth to insert the child at.
In the end, this is what I want:
I have a tree with a root. The root has a list which has 4 children nodes. I want to get the 4 children. For each child generate three nodes. So for child 0 has 3 children, child 1 has 3 children, child 3 has 3 children and child 4 has 3 children. And so forth
Maybe a possible soultion is to have a level attribute on each node and search for that node and then return it's parent. Beacuse it's parent should have a list of all the nodes at the searched for node.
Try this method :
static void getNodesAtDepth(Node root, int currentLevel, int level, List<Node> nodes) {
if(root == null) return;
if(level == 0) {
nodes.add(root);
return;
}
if(currentLevel + 1 == level) {
if(root.getNodeList() != null) {
nodes.addAll(root.getNodeList());
}
}
if(currentLevel < level) {
if(root.getNodeList() != null) {
for(Node node : root.getNodeList()) {
getNodesAtDepth(node, currentLevel + 1, level , nodes);
}
}
}
}
How to use it :
List<Node> nodeList = new LinkedList<>();
getNodesAtDepth(root, 0, 2, nodeList);
root of course is the root of your tree. nodeList will store all your nodes at desired level (in my case it's 2). Second parameter is always 0, (that's for keeping track of the current level)
If I assume your class tree structure is :
class Tree {
List<Tree> children
...
}
Then you can recursively iterate through the tree until you find the expected depth:
void recursivelyCollectNodesAtDepth(int depth,
List<Tree> nodesAtDepth,
Tree tree,
int currentDepth) {
if (tree == null) {
return;
}
if (depth == 0) {
nodesAtDepth.add(tree);
} else if (currentDepth + 1 == depth) {
// add children to the node list when expected depth is reached
if (tree.getChildren() != null) {
nodesAtDepth.addAll(tree.getChildren());
}
} else if (currentDepth < depth) {
// iterate and recursively travers through child nodes
for (Tree childTree : tree.getChildren()) {
recursivelyCollectNodesAtDepth(depth,
nodesAtDepth,
childTree,
currentDepth + 1);
}
}
}
Here the tree nodes a recursively traversed to the expected level
I need to find the number of elements in a tree using an iterative algorithm, but I'm finding the code conceptually very difficult to write.
My approach is to start at the root node and visit the child nodes, then the children of these child nodes, and so on.
This is the code I've written which works for a small tree, but isn't a real solution because I'd need to add an additional block for each level of depth:
// Start the counter at 1 because the root node counts
int size = 1;
for(ITree child1 : root) {
size++;
for(ITree child2 : child1) {
size++;
for(ITree child3 : child2) {
size++;
for(ITree child4 : child3) {
size++;
for(ITree child5 : child4) {
size++;
}
}
}
}
}
return size;
Conceptually, keep a stack (LinkedList, etc.). For each child (now, your child loops), add to the stack. Continue looping through the stack until it is finally empty.
This isn't tested, but this should do exactly what you're looking for. I'm just using java.io.File instead of your "ITree", as it's something I can compile against:
int sizeOfTree(File root){
// Start the counter at 1 because the root node counts
int size = 1;
LinkedList<File> stack = new LinkedList<File>();
stack.add(root);
while(!stack.isEmpty()){
File f = stack.remove();
for(File child : f.listFiles()){
size++;
stack.add(child);
}
}
return size;
}
Using a recursive data structure
It is not practically possible to iteratively traverse a recursive data structure, like a tree with pointers - this is because of the fact that the objects "hide" their underlying data elements.
Using a different data structure
All trees can be stored/implemented as to linear, array data structures, where indices can be calculated using exponential mathematics :
For example, a tree [0, 1, 2, 3, null, 4,null] would describe a tree with 0 at the root, where 0 had direct children 1 and 2. And then 1 has left child "3", and 2 has left child "4".
Thus, if you store the tree this way, the number of elements is, naturally, the number of non-null elements in the array.
Put more simply : Store the tree in a linear structure , and you can know the length at any given time without having to make any kind of fancy algorithm.
The key word for your task is recursion. Tree is a classical recursive structure, so you should write recursive method that accepts root nodes, counts size of this node and then calls itself for all children. Here is pseudo code:
public int getSize(ITree root) {
return getSize(root, 0);
}
private int getSize(ITree node, int size) {
size++;
for(ITree child : node.children()) {
size += getSize(child, size)
}
return size;
}