【问题标题】:Construct a tree structure from list of string paths从字符串路径列表构造树结构
【发布时间】:2009-06-17 07:18:21
【问题描述】:

我在列表中有一组字符串路径,例如 ["x1/x2/x3","x1/x2/x4","x1/x5"]。 我需要从这个列表中构造一个树状结构,可以对其进行迭代以获得漂亮的打印树。 像这样

     x1
    /  \
   x5   x2
       /  \
      x3  x4

有什么想法/建议吗? 我相信可以通过处理字符串列表首先解决问题编辑:选择的正确答案是一个优雅的实现,其他建议也很好。

【问题讨论】:

标签: java tree


【解决方案1】:

遵循可访问树的幼稚实现:

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

输出:

森林 x1 x2 x3 x4 x5

【讨论】:

  • 如何实现这个?任何 github 示例?
  • IndentVisitor 的实现是什么?
  • @Feeco 你可以使用PrintIndentedVisitor 它就像一个魅力
【解决方案2】:

只需通过分隔符拆分每个路径,然后将它们一一添加到树结构中。
即如果'x1' 不存在创建这个节点,如果它存在去它并检查是否有一个孩子'x2' 等等......

【讨论】:

    【解决方案3】:

    我会一次把树做成一串。

    制作一棵空树(它有一个根节点 - 我假设可能有一个类似“x7/x8/x9”的路径)。

    取第一个字符串,将x1添加到根节点,然后将x2添加到x1,然后将x3添加到x2。

    取第二个字符串,看到 x1 和 x2 已经存在,将 x4 添加到 x2。

    对你拥有的每条路径都这样做。

    【讨论】:

      【解决方案4】:

      创建一个对象节点,其中包含一个父节点 (Node) 和一个子节点列表 (Node)。

      首先使用“,”分割字符串。对于每个拆分的字符串,您使用“/”拆分字符串。 在根列表中搜索第一个节点标识符(例如 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);
          }
      }
      

      【讨论】:

        【解决方案5】:

        为数组中的每个字符串创建树。 只需拆分 '/' 的路径,检查该节点是否存在于您的树中,如果存在则继续...否则创建一个新节点并将此节点添加到父节点的子节点中。

        使用递归进行迭代。

        以下是树节点的模型。

        Class Node{
            string name;
            List<Node> childrens;
        
            Node(string name){
                this.name = name;
                this.childrens = new List<Node>();
            }
        }
        

        【讨论】:

          【解决方案6】:

          这就是我从路径(文件夹)结构中创建树的方式。也许应该帮助有基本逻辑的人。

          节点:

          public class Node {
              private String path;
              private List<Node> children;
          
              public Node(String path) {
                  this.path = path;
                  children = new ArrayList<>();
              }
          
              public String getName() {
                  return getName(path);
              }
          
              private String getName(String path) {
                  String[] split = path.split("\\\\");
                  return split[split.length - 1];
              }
          
              public void addChild(Node child) {
                  children.add(child);
              }
          
              public List<Node> getChildren() {
                  return children;
              }
          
              public String getPath() {
                  return path;
              }
          }
          

          文件树:

          public class FilesTree {
              private static final Logger log = Logger.getLogger(FilesTree.class.getName());
          
              private FilesTree() {}
          
              private static void createTree(Node root, List<String> paths) {
                  for (String path : paths) {
                      addNode(root, Arrays.asList(path.split("\\\\")), "");
                  }
              }
          
              private static void addNode(Node node, List<String> path, String nodePath) {
                  if (!path.isEmpty()) {
                      nodePath = nodePath.equals("") ? path.get(0) : String.format("%s\\%s", nodePath, path.get(0));
                  }
          
                  if (node.getChildren().isEmpty() && path.size() == 1) {
                      node.addChild(new Node(nodePath));
                  } else if (!node.getChildren().isEmpty()) {
                      for (Node actual : node.getChildren()) {
                          if (actual.getName().equals(path.get(0))) {
                              addNode(actual, path.subList(1, path.size()), nodePath);
                              return;
                          }
                      }
                      node.addChild(new Node(nodePath));
                  } else {
                      log.info("Without children but with size: " + path.size());
                  }
              }
          }
          

          【讨论】:

          • 您的回答信息量不大;如果你想帮助别人,也许你可以解释一下这个逻辑。
          • 你错过了什么?方法说明?
          • 这个问题并不新鲜;您可以让我们知道您为什么更喜欢这个解决方案,而不是接受的答案,并简要说明您的解决方案的逻辑。
          • 啊,好的。我尝试了这个解决方案,但它们过于复杂,我认为我带来了更简单的解决方案。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多