首页 新闻 会员 周边 捐助

用java流的方式实现树形结构

0
悬赏园豆:100 [待解决问题]

传统的都知道用递归的方式把一个大集合数据实现树形结构展示,能否使用java集合流的方式去实现呢?

hanyaguang的主页 hanyaguang | 初学一级 | 园豆:102
提问于:2023-06-08 09:57
< >
分享
所有回答(4)
1

可以使用 Java 8 引入的流式操作 (Stream API) 来实现将一个大集合数据转换成树形结构并进行展示。下面是一个基本的思路:

  1. 将集合数据按照所要实现的树形结构的标准进行排序;
  2. 使用 Stream#collect 方法,指定一个收集器 Collector,将流式操作的结果转换为想要的树形结构;
  3. 根据生成的树形结构进行页面的展示。

举个例子,假设有一个节点类 Node,其结构包含以下信息:

  • id:节点的唯一 ID
  • parentId:该节点的父节点 ID
  • name:节点的名称

那么可以通过以下方法将 List<Node> 转化为树形结构:

// 定义 Node 类,省略 getter/setter 方法
public class Node {
    private int id;
    private int parentId;
    private String name;
}
// 构造树形结构
public static Node buildTree(List<Node> nodes) {
    // 首先找到根节点
    Node root = nodes.stream()
        .filter(node -> node.getParentId() == 0)  // 假设根节点的 parentId = 0
        .findFirst()
        .orElseThrow(() -> new IllegalArgumentException("根节点不存在"));

    // 处理子节点
    for (Node parent : nodes) {
        if (parent.getParentId() == 0) continue;
        for (Node child : nodes) {
            if (child.getParentId() == parent.getId()) {
                parent.addChild(child);
            }
        }
    }

    return root;
}

在上述代码中,首先通过 Stream API 找到根节点。然后借助流式操作,进一步处理子节点并形成树形结构。例如,在 Node 类中增加一个 addChild() 方法用于添加子节点:

public class Node {
    // 其他属性与方法省略

    private List<Node> children = new ArrayList<>(16);

    public void addChild(Node child) {
        this.children.add(child);
    }
}

通过在上述 buildTree() 方法中的双重循环遍历判断来添加节点到其父节点下面。

当这个树形结构生成后,接下来就可以进行页面展示了。使用递归方式遍历整颗数,将树形结构转换为页面所需的 HTML 结构。

lanedm | 园豆:2396 (老鸟四级) | 2023-06-08 10:52

非常感谢您的回答,试了一下基本实现了此功能。就是您写的时候可能没想太多,if (parent.getParentId() == 0) continue; 在循环的时候不能把这个过滤掉,如果过滤了也就给根上不加子节点了。或者根据你那个思路也有其他的修正方式。总之非常感谢哈。

支持(0) 反对(0) hanyaguang | 园豆:102 (初学一级) | 2023-06-08 14:42

@hanyaguang: 为了避免此问题,我们可以先将所有节点按照 ParentId 进行分组,然后从根节点开始对其子节点进行递归添加操作。

public static Node buildTree(List<Node> nodes) {
    // 使用 map 对节点进行分组,key 是 parentId,value 是该 parentId 下的所有节点列表
    Map<Integer, List<Node>> parentToChildren = nodes.stream().collect(Collectors.groupingBy(Node::getParentId));

    // 定义递归函数,将当前节点加入到其父节点下面,并返回当前节点
    Function<Node, Node> addChildToParent = node -> {
        int parentId = node.getParentId();

        if (parentId == 0) {
            return node;  // 如果当前节点没有父节点,说明它是根节点,直接返回即可
        }

        Node parent = nodes.stream()
                .filter(n -> n.getId() == parentId)
                .findFirst()
                .orElse(null);

        if (parent != null) {
            parent.addChild(node);  // 将当前节点添加到父节点下
        }

        return node;
    };

    // 对每一个叶子节点执行递归函数,最终返回根节点
    return nodes.stream()
            .map(addChildToParent)
            .filter(node -> node.getParentId() == 0)
            .findFirst()
            .orElse(null);
}

首先,我们使用 Collectors.groupingBy() 方法将节点按照 ParentId 进行分组,得到一个 Map。接着,定义一个递归函数 addChildToParent,该函数接受一个节点作为输入参数,并将该节点加入到其父节点的子节点列表中。

最后,在主代码段中,对每个节点执行 addChildToParent 函数,并将过滤后的根节点返回。这样就可以有效地生成一颗正确的树形结构了。

支持(1) 反对(0) lanedm | 园豆:2396 (老鸟四级) | 2023-06-08 14:46
0

是的,你可以使用 Java 8+ 的流(Stream)API 来实现树形结构。虽然递归是常见的方式,但使用流也可以达到相同的效果。下面是一个简单的示例,演示如何使用 Java 流来构建树形结构。

首先,我们需要定义一个包含节点信息的类,例如:

java
Copy code
class TreeNode {
private String id;
private String parentId;
private List<TreeNode> children;

// 构造函数、Getter和Setter省略

}
然后,假设我们有一个包含节点信息的列表,我们可以使用流的方式构建树形结构:

java
Copy code
List<TreeNode> nodeList = ...; // 假设这是原始的节点列表

// 构建根节点列表,这里假设根节点的 parentId 为 null
List<TreeNode> roots = nodeList.stream()
.filter(node -> node.getParentId() == null)
.collect(Collectors.toList());

// 递归构建树
roots.forEach(root -> buildTree(root, nodeList));

// 递归方法,用于构建子节点
private void buildTree(TreeNode parent, List<TreeNode> nodeList) {
List<TreeNode> children = nodeList.stream()
.filter(node -> parent.getId().equals(node.getParentId()))
.collect(Collectors.toList());

parent.setChildren(children);

children.forEach(child -> buildTree(child, nodeList));

}
在上述代码中,我们首先通过过滤 parentId 为 null 的节点,获取根节点列表。然后,使用递归的方式构建树,遍历根节点列表,为每个根节点找到对应的子节点,并将子节点设置为父节点的 children 属性。递归地对每个子节点执行相同的操作,直到树的每个节点都被处理完毕。

注意,上述代码中使用了递归调用的方式,因此它并不是纯粹的流式操作。流主要用于筛选、映射和收集节点,而递归用于构建树形结构。但是,通过结合流和递归,你可以利用 Java 8+ 的强大特性来构建树形结构。

希望这可以帮助你实现树形结构的构建。如果你有其他问题,请随时提问。

Technologyforgood | 园豆:7775 (大侠五级) | 2023-06-08 23:08

谢谢您的回答,这个思路好像更清晰一些。

支持(0) 反对(0) hanyaguang | 园豆:102 (初学一级) | 2023-06-09 09:27
0
Java集合流(Stream)可以用于对集合中的元素进行过滤、映射、排序等操作,但是它并不是用来表示树形结构的。如果您想要展示树形结构,可以考虑使用Java中的树形数据结构,如TreeNode或者TreeMap等。

下面是一个简单的例子,使用TreeNode来展示树形结构:

import java.util.ArrayList;
import java.util.List;

public class TreeNode {
    private String name;
    private List<TreeNode> children = new ArrayList<>();

    public TreeNode(String name) {
        this.name = name;
    }

    public void addChild(TreeNode child) {
        children.add(child);
    }

    public List<TreeNode> getChildren() {
        return children;
    }

    public String getName() {
        return name;
    }

    public static void main(String[] args) {
        TreeNode root = new TreeNode("root");
        TreeNode node1 = new TreeNode("node1");
        TreeNode node2 = new TreeNode("node2");
        TreeNode node3 = new TreeNode("node3");
        TreeNode node4 = new TreeNode("node4");
        TreeNode node5 = new TreeNode("node5");
        TreeNode node6 = new TreeNode("node6");

        root.addChild(node1);
        root.addChild(node2);
        node1.addChild(node3);
        node1.addChild(node4);
        node2.addChild(node5);
        node2.addChild(node6);

        printTree(root, 0);
    }

    private static void printTree(TreeNode node, int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("  ");
        }
        System.out.println(node.getName());
        for (TreeNode child : node.getChildren()) {
            printTree(child, depth + 1);
        }
    }
}
在这个例子中,我们定义了一个TreeNode类,它包含一个名字和一个子节点列表。我们可以通过addChild()方法向节点中添加子节点,通过getChildren()方法获取子节点列表,通过getName()方法获取节点的名字。

在main()方法中,我们创建了一个树形结构,并通过printTree()方法递归地打印出了整个树形结构。在printTree()方法中,我们使用了深度优先遍历的方式来遍历树形结构,并使用depth参数来控制每个节点的缩进层数,从而形成树形结构的展示效果。

您可以根据自己的需求修改这个例子,来实现您所需要的树形结构展示效果。
ycyzharry | 园豆:25683 (高人七级) | 2023-06-11 03:27
0

可以使用Java 8的Stream API实现树形结构展示。以下是一个例子:

假设你有一个包含多个节点的列表,每个节点都有一个唯一的ID和一个父节点ID,你可以使用以下步骤构建树形结构:

  1. 定义节点数据结构:
public class TreeNode {
    private Integer nodeId;
    private Integer parentId;
    // 其他属性

    // getter和setter方法
}
  1. 对节点列表进行分组,以父节点ID作为键值:
Map<Integer, List<TreeNode>> nodesGrouped = nodes.stream()
                                                .collect(Collectors.groupingBy(TreeNode::getParentId));
  1. 构建树形结构:
public static TreeNode buildTree(List<TreeNode> nodes, Integer rootId) {
    Map<Integer, List<TreeNode>> nodesMap = nodes.stream().collect(Collectors.groupingBy(TreeNode::getParentId));
    TreeNode rootNode = nodes.stream().filter(node -> rootId.equals(node.getNodeId())).findAny().orElse(null);
    if (rootNode != null) {
        rootNode.setChildren(findChildren(nodesMap, rootNode.getNodeId()));
    }
    return rootNode;
}

private static List<TreeNode> findChildren(Map<Integer, List<TreeNode>> nodesMap, Integer parentId) {
    List<TreeNode> children = nodesMap.get(parentId);
    if (children != null) {
        children.forEach(child -> child.setChildren(findChildren(nodesMap, child.getNodeId())));
    }
    return children;
}

在上面的代码中,我们首先将节点列表按照父节点ID分组,然后根据传入的根节点ID查找根节点的信息。

接着,我们递归遍历子节点,根据父节点ID查找所有子节点,并将其设置为当前节点的孩子节点。如果没有孩子节点,则当前节点的孩子节点为空。

最后,我们返回根节点即可。通过这种方式,我们就可以使用Java 8的Stream API实现树形结构的展示了。

小九九呀 | 园豆:383 (菜鸟二级) | 2023-06-17 20:00
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册