2009-06-17 17 views
16

リストに["x1/x2/x3"、 "x1/x2/x4"、 "x1/x5"]のような文字列パスの集合があります。 私はこのリストから、かなり印刷されたツリーを得るために反復することができる木のような構造を構築する必要があります。 このように文字列パスのリストからツリー構造を構築します

x1 
| 
|-x2 
| | 
| |-x3 
| | 
| |-x4 
| 
|-x5 

アイデア/提案はありますか? 私は、問題が文字列のリストを処理することによって最初に攻撃されることができると信じて編集:正しい答えはエレガントな実装だった、他の提案も良かった。

+0

はたぶん、あなたは(と私)の問題を解決します私の現在の作業の実装を読み興味があるだろう:)を見てみましょう:のhttp:/ /stackoverflow.com/a/10935115/737636 – StErMi

答えて

32

は、訪問可能木の素朴な実装の実装フォロー:Visitorパターンのための

class Tree<T> implements Visitable<T> { 

    // NB: LinkedHashSet preserves insertion order 
    private final Set<Tree> children = new LinkedHashSet<Tree>(); 
    private final T data; 

    Tree(T data) { 
     this.data = data; 
    } 

    void accept(Visitor<T> visitor) { 
     visitor.visitData(this, data); 

     for (Tree child : children) { 
      Visitor<T> childVisitor = visitor.visitTree(child); 
      child.accept(childVisitor); 
     } 
    } 

    Tree child(T data) { 
     for (Tree child: children) { 
      if (child.data.equals(data)) { 
       return child; 
      } 
     } 

     return child(new Tree(data)); 
    } 

    Tree child(Tree<T> child) { 
     children.add(child); 
     return child; 
    } 
} 

インタフェース:

interface Visitor<T> { 

    Visitor<T> visitTree(Tree<T> tree); 

    void visitData(Tree<T> parent, T data); 
} 

interface Visitable<T> { 

    void accept(Visitor<T> visitor); 
} 

サンプルを訪問者パターンの実装:

class PrintIndentedVisitor implements Visitor<String> { 

    private final int indent; 

    PrintIndentedVisitor(int indent) { 
     this.indent = indent; 
    } 

    Visitor<String> visitTree(Tree<String> tree) { 
     return new IndentVisitor(indent + 2); 
    } 

    void visitData(Tree<String> parent, String data) { 
     for (int i = 0; i < indent; i++) { // TODO: naive implementation 
      System.out.print(" "); 
     } 

     System.out.println(data); 
    } 
} 

そして最後に(!!!)簡単なテストケース:

Tree<String> forest = new Tree<String>("forest"); 
    Tree<String> current = forest; 

    for (String tree : Arrays.asList("x1/x2/x3", "x1/x2/x4", "x1/x5")) { 
     Tree<String> root = current; 

     for (String data : tree.split("/")) { 
      current = current.child(data); 
     } 

     current = root; 
    } 

    forest.accept(new PrintIndentedVisitor(0)); 

出力:

 
forest 
    x1 
    x2 
     x3 
     x4 
    x5 
+2

コードdfaありがとうございました。それは魅力のように働く。 ビジターパターンの実装はきれいです。 – sushant

+1

結婚してください!非常に有益な答えをありがとう。 – ctrlplusb

+0

これはどのように実装するのですか?どんなgithubの例ですか? – TheOnlyAnil

3

私は一度に1つの文字列を作ります。

空のツリーを作成します(ルートノードがあります。「x7/x8/x9」などのパスがあると仮定します)。

最初の文字列をとり、x1をルートノードに追加し、次にx2をx1に、次にx3をx2に追加します。

x1とx2がすでにあることを確認し、x4をx2に追加します。

これは、すべてのパスで行います。

10

各パスをデリミタで区切り、ツリー構造に1つずつ追加するだけです。
すなわち'x1'

2

は、親(ノード)と含まれているオブジェクトのノードを作成します...それはそれに行く存在などがあり、子供'x2'で、かどうかを確認しなければ、このノードを作成して存在していない場合子のリスト(ノード)。

最初に "、"を使用して文字列を分割します。分割されたすべての文字列に対して、 "/"を使用して文字列を分割します。 ルートリストの最初のノード識別子(たとえばx1)を検索します。 見つけられたら、ノードを使用して次のノード識別子(たとえばx2)を見つけます。

ノードが見つからない場合は、既存のリストで見つけられた最後のノードにノードを追加します。

リスト構造を作成したら、そのリストを画面に印刷できます。私はそれを再帰的にするだろう。テストの対象外となった

、単にアニメーション

public void print(List nodes, int deep) { 
    if (nodes == null || nodes.isEmpty()) { 
     return; 
    } 

    StringBuffer buffer = new StringBuffer(); 
    for (int i = 0; i < deep; i++) { 
     buffer.append("---"); 
    } 

    for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { 
     Node node = (Node)iterator.next(); 

     System.out.println(buffer.toString() + " " + node.getIdentifier()); 

     print(node.getChildren(), deep + 1); 
    } 
}