JAVA 获取树的所有路径-深度优先遍历和广度优先

1、示例

树的结构
示例中本身构建了图片中的这棵树
示例中本身构建了图片中的这棵树
树节点模型:

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、遍历方式

① 递归形式的深度优先遍历

/**
     * 深度优先遍历(递归方式) --- 树(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;
    }

③ 广度优先遍历,遍历全部叶子路径

/**
     * 广度优先遍历 ---- 查找树的全部叶子路径
     * 
     * @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 ” 的分支:

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]]
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
深度优先遍历广度优先遍历是图的两种常见遍历算法。 深度优先遍历(DFS)是一种递归算法,它从图中的某个节点开始,首先访问该节点,然后遍历该节点的所有邻接节点,再依次对每个邻接节点进行深度优先遍历。换句话说,DFS会沿着图的一条路径一直往下遍历,直到遇到没有未访问过的邻接节点为止,再返回上一级节点继续遍历其他未访问过的节点。DFS的实现一般使用递归或栈来保存待访问节点。 广度优先遍历(BFS)是一种队列的算法,它从图中的某个节点开始,首先访问该节点,然后遍历该节点的所有邻接节点,并将这些邻接节点加入队列中。接下来从队列中取出一个节点,再依次遍历该节点的邻接节点,并将未访问过的邻接节点加入队列中,如此往复直到队列为空。BFS的实现一般使用队列来保存待访问节点。 在视频中,可以演示通过图的邻接矩阵或邻接表的形式来表示图,并使用Java代码来实现深度优先遍历广度优先遍历。对于深度优先遍历,可以从图中的某个节点开始递归地遍历它的邻接节点,并使用一个标记数组来记录节点是否已经访问过。对于广度优先遍历,可以使用一个队列来按照广度优先的顺序遍历图中的节点,并同样使用标记数组来记录节点是否已经访问过。 通过这个视频,观众可以了解到深度优先遍历广度优先遍历的原理和实现方法,并通过代码示例更好地理解其过程。这些算法在图的遍历、路径查找等问题中应用广泛,对于理解和解决相关问题具有重要意义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值