【问题标题】:Getting paths from root to leaves in a specific tree encoding以特定的树编码获取从根到叶的路径
【发布时间】:2011-07-19 16:04:44
【问题描述】:

我有一棵树表示为Set<Integer>[]

以下Set<Integer>[]

[ { 1 }, { 2, 3 }, { 4 }, { 5, 6, 7 } ]

代表以下树:

      1
     / \
    /   \
   /     \
  2       3
  |       |
  4       4
 /|\     /|\
5 6 7   5 6 7

所以树中的每一层都被编码为Set。树中特定级别的所有子集都是相同的。第一个集合中可以有多个整数。

我想从Set<Integer>[] 获取从根到叶子的所有路径的列表:

[ [ 1, 2, 4, 5 ], [ 1, 2, 4, 6 ], [ 1, 2, 4, 7 ], [ 1, 3, 4, 5 ], [ 1, 3, 4, 6 ], [ 1, 3, 4, 7 ] ]

【问题讨论】:

  • 只是为了澄清一下,树是表示为一组数组还是一组数组?我有点困惑。
  • @Wesam:问题说明:Set<Integer>[],所以这是Set<Integer> 的数组。

标签: java data-structures tree


【解决方案1】:

在树中搜索的关键通常是实现一个很好的 Ajacency 函数,它为特定节点提供相邻节点。

对于这棵树,邻接函数会想要找到节点所在的层级,然后将下一层的节点作为相邻节点返回。它看起来像这样:

  /**
   * This returns the adjacent nodes to an integer node in the tree
   * @param node
   * @return a set of adjacent nodes, and null otherwise
   */
  public Set<Integer> getAdjacentsToNode(Integer node) {

    for (int i = 0; i < tree.size(); i++) {
      Set<Integer> level = tree.get(i);
      if (level.contains(node) && i < tree.size() - 1) {
        return tree.get(i + 1);
      }
    }
    return null;
  }

假设我们已经将树定义为类中的一个字段。

在我们运行搜索之前,我们希望适当地初始化设置根目录并对路径做一些准备工作。因此,我们执行以下操作:

/**
 * initializes our search, sets the root and adds it to the path
 */
  public void initialize() {
    root = -1;
    for (Integer node : tree.get(0)) {
      root = node;
    }
    currentPath.add(root);
  }

假设currentPathroot 已经定义为字段。

然后,我们在树上运行 DFS 搜索,在遍历树时将每个节点附加到当前路径,并将该路径添加到我们设置的路径中,并在到达死角(叶子)时重置它:

  /**
   * runs a DFS on the tree to retrieve all paths
   * @param tree
   */
  public void runDFS(Integer node) {
    if (getAdjacentsToNode(node) != null) {
      for (Integer adjNode : getAdjacentsToNode(node)) {
        currentPath.add(adjNode);
        runDFS(adjNode);
      }
      currentPath.remove(currentPath.size() -1);
    } else {
      paths.add(currentPath.toArray(new Integer[0]));
      currentPath.remove(currentPath.size() -1);
    }
  }

因此,整个班级看起来像这样:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class DFS {
  private List<Integer> currentPath = new ArrayList<Integer>();
  private List<Integer[]> paths = new ArrayList<Integer[]>();
  private ArrayList<Set<Integer>> tree;
  private Integer root;
  /**
   * constructor
   * @param tree
   */
  public DFS(ArrayList<Set<Integer>> tree) { 
    this.tree = tree;
  }

  public List<Integer[]> getPaths() {
    return paths;
  }
  public void setPaths(List<Integer[]> paths) {
    this.paths = paths;
  }
  public Integer getRoot() {
    return root;
  }
  public void setRoot(Integer root) {
    this.root = root;
  }

/**
 * initializes our search, sets the root and adds it to the path
 */
  public void initialize() {
    root = -1;
    for (Integer node : tree.get(0)) {
      root = node;
    }
    currentPath.add(root);
  }

  /**
   * This returns the adjacent nodes to an integer node in the tree
   * @param node
   * @return a set of adjacent nodes, and null otherwise
   */
  public Set<Integer> getAdjacentsToNode(Integer node) {

    for (int i = 0; i < tree.size(); i++) {
      Set<Integer> level = tree.get(i);
      if (level.contains(node) && i < tree.size() - 1) {
        return tree.get(i + 1);
      }
    }
    return null;
  }

  /**
   * runs a DFS on the tree to retrieve all paths
   * @param tree
   */
  public void runDFS(Integer node) {
    if (getAdjacentsToNode(node) != null) {
      for (Integer adjNode : getAdjacentsToNode(node)) {
        currentPath.add(adjNode);
        runDFS(adjNode);
      }
      currentPath.remove(currentPath.size() -1);
    } else {
      paths.add(currentPath.toArray(new Integer[0]));
      currentPath.remove(currentPath.size() -1);
    }
  }
}

为了测试它,我们试试这个:

public static void main(String[] args) { 
    ArrayList<Set<Integer>> tree = new ArrayList<Set<Integer>>();
    Set<Integer> level1 = new HashSet<Integer>();
    level1.add(new Integer(1));

    Set<Integer> level2 = new HashSet<Integer>();
    level2.add(new Integer(2));
    level2.add(new Integer(3));

    Set<Integer> level3 = new HashSet<Integer>();
    level3.add(new Integer(4));

    Set<Integer> level4 = new HashSet<Integer>();
    level4.add(new Integer(5));
    level4.add(new Integer(6));
    level4.add(new Integer(7));

    tree.add(level1);
    tree.add(level2);
    tree.add(level3);
    tree.add(level4);

    DFS dfsSearch = new DFS(tree); 
    dfsSearch.initialize();
    dfsSearch.runDFS(dfsSearch.getRoot());

    for (Integer[] path : dfsSearch.getPaths()) { 
      System.out.println(Arrays.toString(path));
    }

我们得到以下输出:

[1, 2, 4, 5]
[1, 2, 4, 6]
[1, 2, 4, 7]
[1, 3, 4, 5]
[1, 3, 4, 6]
[1, 3, 4, 7]

【讨论】:

    【解决方案2】:

    试试这样的:

    public static List<Integer[]> getAllPaths(Set<Integer>[] tree){
    
        // Get the overall number of path
        int totalSize = 1;
        for(Set<Integer> line : tree){
            totalSize *= line.size();
        }
    
        // Create the empty paths
        List<Integer[]> allPaths = new ArrayList<Integer[]>(totalSize);
        for(int i = 0 ; i<totalSize ; ++i){
            Integer[] path = new Integer[tree.length];
            allPaths.add(path);
        }
    
        // Fill the paths
        int indexLine = 0;
        for (Set<Integer> line : tree) {
            Iterator<Integer[]> pathIterator = allPaths.iterator();
            Iterator<Integer> lineIterator = line.iterator();
            while(pathIterator.hasNext()){
                if(!lineIterator.hasNext()){
                    lineIterator = line.iterator();
                }
                pathIterator.next()[indexLine] = lineIterator.next();
            }
            ++indexLine;
        }
        return allPaths;
    }
    

    它适用于您的示例:

    public static void main(String[] args) {
    
        Set<Integer> line1 = new HashSet<Integer>();
        line1.add(new Integer(1));
        Set<Integer> line2 = new HashSet<Integer>();
        line2.add(new Integer(2));
        line2.add(new Integer(3));
        Set<Integer> line3 = new HashSet<Integer>();
        line3.add(new Integer(4));
        Set<Integer> line4 = new HashSet<Integer>();
        line4.add(new Integer(5));
        line4.add(new Integer(6));
        line4.add(new Integer(7));
    
        Set[] test = {line1, line2,line3,line4};
    
        List<Integer[]> allPaths = getAllPaths(test);
    
        for(Integer[] path : allPaths){
            System.out.println(Arrays.toString(path));
        }
    }
    

    【讨论】:

      【解决方案3】:

      我不打算编写代码,但最简单的方法是深度优先遍历,在每个级别您将每个条目附加到当前路径。

      此外,您的返回值将是列表的集合(或数组)(因为垂直路径不能是无序集)。

      在伪代码中:

      def getPaths(levels) {
        return getPaths(levels, 0, new Set())
      }
      
      def getPaths(levels, currentIndex, paths) {
      
        if(currentIndex == levels.length)
          return paths
      
        def newPaths = new Set(paths)
      
        for(path : paths) {
          for(level : levels) {
            newPaths.add( path + level )
          }
        }
      
        return getPaths(levels, currentIndex + 1, newPaths)
      
      }
      

      【讨论】:

        猜你喜欢
        • 2011-07-12
        • 2016-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-31
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多