深入到所有终端节点的第一个搜索列表路径

时间:2014-06-27 12:52:23

标签: java graph-algorithm

您好我有一棵树,我希望从初始(根)节点到所有叶子获取路径。

我发现了几个算法列出了(在图表中任何给定的两个节点之间的所有)apths(例如这个SO问题: Graph Algorithm To Find All Connections Between Two Arbitrary Vertices

对于二叉树,还存在一种算法 http://techieme.in/print-all-paths-in-a-tree/ 但我在一棵树上工作,有各种分支因素。

有没有更好的方法来实现我想做的事情,而不是遍历树一次以获得所有叶子,然后针对所有叶子和初始节点运行上面的算法?

我正在考虑实现一些额外堆栈扩展的简单DFS,其中包含沿着路径到达单个叶子的所有节点,然后通过循环遍历这些堆栈来列出所有句子。

    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());
            }
        }
    }

更新 这个问题是,为了生成完整的句子,人们会回到根。所以我想问题是:如何记住已经完全访问过的节点(这意味着已经探索过所有子节点)?

4 个答案:

答案 0 :(得分:3)

打印从根到每个叶子的所有路径意味着打印整个树,所以我只使用一个简单的DFS并为每个节点执行以下操作:

  • 将其添加到列表/堆栈
  • 如果节点有子节点,则为子节点重复
  • 如果节点是叶子,则打印列表/堆栈
  • 从列表/堆栈中弹出节点

示例:

   A
  / \
 B   E
/ \ / \
C D F G

第一步看起来像这样:

  • 将A放在列表中 - &gt; {A}
  • 将B放在列表中 - &gt; {A,B}
  • 将C放在列表中 - &gt; {A,B,C}
  • 由于C是叶子,打印列表(A,B,C)
  • 从列表中删除C - &gt; {A,B}
  • 将D放在列表中 - &gt; {A,B,d}
  • 由于D是叶子,打印列表(A,B,D)
  • ...

答案 1 :(得分:0)

如果您知道图形确实是一个树(每个节点只有一条路径),它们是的,简单的DFS会更有效(至少从内存使用的角度来看)。否则,您也可以使用iterative deepening DFS

答案 2 :(得分:0)

所以这是一个示例方法。请注意,您的节点结构中需要额外的visited字段:

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;
}

答案 3 :(得分:0)

略微修改DFS(包括反向跟踪)会打印来自给定源的所有路径。在下面的示例中,图表以邻接列表格式表示。

  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;
  }