遍歷樹,找出全部葉子路徑

1、示例:

樹的結構:node

示例中本身構建了圖片中的這棵樹:ide

樹節點模型:

public class TreeNode {
    String value;
    List<TreeNode> children;

    public TreeNode() {
        children = new ArrayList<>();
    }

    public TreeNode(String value) {
        this.value = value;
        children = new ArrayList<>();
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return value;
    }
}

構建樹:

// 建立一棵樹
TreeNode root = new TreeNode("A");
// 第二層
root.children.add(new TreeNode("B"));
root.children.add(new TreeNode("C"));
// 第三層
root.children.get(0).children.add(new TreeNode("D"));
root.children.get(0).children.add(new TreeNode("E"));
root.children.get(1).children.add(new TreeNode("F"));
root.children.get(1).children.add(new TreeNode("H"));
root.children.get(1).children.add(new TreeNode("G"));
// 第四層
root.children.get(0).children.get(1).children.add(new TreeNode("I"));

2、遍歷方式

提供三種方式進行遍歷:this

① 遞歸形式的深度優先遍歷:

/**
     * 深度優先遍歷(遞歸方式) --- 樹(Tree)
     */
    public void recurTree(TreeNode root) {
        List<List<String>> result = new ArrayList<>();
        List<String> path = new ArrayList<>();
        path.add(root.value);
        findPath(result, root, path);
        System.out.println(result);
    }

    private void findPath(List<List<String>> result, TreeNode node, List<String> path) {
        if (node.children == null || node.children.size() <= 0) {
            result.add(path);
            return;
        }

        for (int i = 0; i < node.children.size(); i++) {
            TreeNode child = node.children.get(i);
            List<String> cPath = new ArrayList<>();
            cPath.addAll(path);
            cPath.add(child.value);
            findPath(result, child, cPath, target);
        }
    }

② 非遞歸的深度優先遍歷

/**
     * 深度優先遍歷(非遞歸方式) ----- 查找樹的全部葉子路徑
     * 
     * @param root
     *            根節點
     * @return 葉子路徑的集合
     */
    public List<List<TreeNode>> dfsTree(TreeNode root) {
        Stack<TreeNode> nodeStack = new Stack<>();
        Stack<List<TreeNode>> pathStack = new Stack<>();
        List<List<TreeNode>> result = new ArrayList<>();
        nodeStack.push(root);
        ArrayList<TreeNode> arrayList = new ArrayList<>();
        arrayList.add(root);
        pathStack.push(arrayList);

        while (!nodeStack.isEmpty()) {
            TreeNode curNode = nodeStack.pop();
            List<TreeNode> curPath = pathStack.pop();

            if (curNode.children == null || curNode.children.size() <= 0) {
                result.add(curPath);
            } else {
                int childSize = curNode.children.size();
                for (int i = childSize - 1; i >= 0; i--) {
                    TreeNode node = curNode.children.get(i);
                    nodeStack.push(node);
                    List<TreeNode> list = new ArrayList<>(curPath);
                    list.add(node);
                    pathStack.push(list);
                }
            }
        }
        return result;
    }

3. 廣度優先遍歷,遍歷全部葉子路徑

/**
     * 廣度優先遍歷 ---- 查找樹的全部葉子路徑
     * 
     * @param root
     *            根節點
     * @return 葉子路徑的集合
     */
    public List<List<TreeNode>> bfsTree(TreeNode root) {
        Queue<TreeNode> nodeQueue = new LinkedList<>();
        Queue<List<TreeNode>> qstr = new LinkedList<>();
        List<List<TreeNode>> result = new ArrayList<>();
        nodeQueue.add(root);
        ArrayList<TreeNode> arrayList = new ArrayList<>();
        qstr.add(arrayList);

        while (!nodeQueue.isEmpty()) {
            TreeNode curNode = nodeQueue.remove();
            List<TreeNode> curList = qstr.remove();

            if (curNode.children == null || curNode.children.size() <= 0) {
                curList.add(curNode);
                result.add(curList);
            } else {
                for (int i = 0; i < curNode.children.size(); i++) {
                    TreeNode treeNode = curNode.children.get(i);
                    nodeQueue.add(treeNode);
                    List<TreeNode> list = new ArrayList<>(curList);
                    list.add(curNode);
                    qstr.add(list);
                }
            }
        }

        return result;
    }

三種方式的輸出:

深度優先遍歷(遞歸):[[A, B, D], [A, B, E, I], [A, C, F], [A, C, H], [A, C, G]]
廣度優先遍歷:[[A, B, D], [A, C, F], [A, C, H], [A, C, G], [A, B, E, I]]
深度優先遍歷(非遞歸):[[A, B, D], [A, B, E, I], [A, C, F], [A, C, H], [A, C, G]]

3、總結

  示例是查找樹的全部葉子節點,觸類旁通,若是咱們是查找樹中知足某個條件的路徑,也是很是容易了。好比下面中查找 「 E 」 的分支:spa

public void recurTree(TreeNode root) {
        List<List<String>> result = new ArrayList<>();
        List<String> path = new ArrayList<>();
        path.add(root.value);
        findPath(result, root, path, "E");
        System.out.println(result);
    }

    private void findPath(List<List<String>> result, TreeNode node, List<String> path, String target) {
        if (target.equals(node.value)) {
            result.add(path);
            return;
        }

        if (node.children == null || node.children.size() <= 0) {
            return;
        }

        for (int i = 0; i < node.children.size(); i++) {
            TreeNode child = node.children.get(i);
            List<String> cPath = new ArrayList<>();
            cPath.addAll(path);
            cPath.add(child.value);
            if (result.size() > 0)
                break;
            findPath(result, child, cPath, target);
        }
    }

輸出:

[[A, B, E]]
相關文章
相關標籤/搜索