惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Troy Hunt's Blog
P
Proofpoint News Feed
Help Net Security
Help Net Security
T
The Exploit Database - CXSecurity.com
Recent Commits to openclaw:main
Recent Commits to openclaw:main
NISL@THU
NISL@THU
Forbes - Security
Forbes - Security
N
News and Events Feed by Topic
C
CERT Recently Published Vulnerability Notes
Simon Willison's Weblog
Simon Willison's Weblog
Hacker News: Ask HN
Hacker News: Ask HN
P
Privacy International News Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Hacker News - Newest:
Hacker News - Newest: "LLM"
云风的 BLOG
云风的 BLOG
博客园 - 【当耐特】
S
Secure Thoughts
爱范儿
爱范儿
Jina AI
Jina AI
H
Heimdal Security Blog
量子位
罗磊的独立博客
人人都是产品经理
人人都是产品经理
T
Threat Research - Cisco Blogs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Cisco Talos Blog
Cisco Talos Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
MyScale Blog
MyScale Blog
T
Tor Project blog
博客园_首页
T
Tenable Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
T
Threatpost
The GitHub Blog
The GitHub Blog
P
Proofpoint News Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Security Archives - TechRepublic
Security Archives - TechRepublic
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Latest news
Latest news
AWS News Blog
AWS News Blog
Y
Y Combinator Blog
Martin Fowler
Martin Fowler
Last Week in AI
Last Week in AI
V
Visual Studio Blog
The Hacker News
The Hacker News
I
Intezer
L
LINUX DO - 最新话题
L
LangChain Blog
W
WeLiveSecurity

博客园 - wastonl

Spring异步任务和定时任务 Spring ResolvableType说明 Jvm内存以及垃圾回收相关知识 RocketMQ如何保证消息可靠性 RocketMQ整体架构 mybatis-plus易忘点笔记 SpringMVC使用Resource实现二进制传输(下载) Spring事件异步执行设计与实现 Spring Bean销毁机制 Spring Lifecycle组件 Zipkin Brave使用 Spring Boot日志系统简要介绍 spring cloud sleuth基本使用 Spring懒加载与@Lazy注解 tomcat自动刷新响应输出流缓冲区 https碎碎念 ES脚本使用 SpringMVC静态资源处理 Maven插件运行方式 如何使用Maven将项目中的依赖打进jar包 时区以及时区对于Java时间类格式化的影响 SpringMVC处理请求头、响应头、编码行为 tomcat连接处理机制和线程模型 JWT示例与原理 方法句柄API使用
树组件实现
wastonl · 2024-07-02 · via 博客园 - wastonl

作用

提供一个通用的树组件模型,用于将元素列表转成树节点。

实现

元素节点定义

public interface TreeNodeElement {

    /**
     * 当前节点key
     */
    String getKey();

    /**
     * 父节点key
     */
    String getParentKey();
}

树节点定义

package com.wangtao.springboot3.common;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonUnwrapped;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class TreeNode<T extends TreeNodeElement> {

    /**
     * 将元素中的属性展开到当前节点中
     */
    @JsonUnwrapped
    private final T element;

    @JsonIgnore
    private TreeNode<T> parent;

    private final List<TreeNode<T>> children;

    private TreeNode(T element) {
        this.element = element;
        this.children = new ArrayList<>();
    }

    public void addChild(TreeNode<T> child) {
        this.children.add(child);
    }

    public void addChildren(List<TreeNode<T>> children) {
        this.children.addAll(children);
    }

    public void setChildren(List<TreeNode<T>> children) {
        Objects.requireNonNull(children, "children must not be null!");
        this.children.clear();
        this.children.addAll(children);
    }

    public List<TreeNode<T>> getChildren() {
        return Collections.unmodifiableList(this.children);
    }

    public T getElement() {
        return element;
    }

    public void setParent(TreeNode<T> parent) {
        this.parent = parent;
    }

    public TreeNode<T> getParent() {
        return parent;
    }

    public static <T extends TreeNodeElement> TreeNode<T> of(T element) {
        return new TreeNode<>(element);
    }

    /**
     * 构建树
     * O(n)时间复杂度
     * @param elements 元素列表
     * @return 树节点列表
     */
    public static <T extends TreeNodeElement> List<TreeNode<T>> build(List<T> elements) {
        Objects.requireNonNull(elements, "elements must not be null!");
        List<TreeNode<T>> treeNodes = new ArrayList<>();
        Map<String, TreeNode<T>> treeNodeMap = elements.stream()
                .collect(Collectors.toMap(TreeNodeElement::getKey, TreeNode::of));
        for (T element : elements) {
            TreeNode<T> self = treeNodeMap.get(element.getKey());
            TreeNode<T> parent = treeNodeMap.get(element.getParentKey());
            if (Objects.nonNull(parent)) {
                self.setParent(parent);
                parent.addChild(self);
            } else {
                // 顶级节点
                treeNodes.add(self);
            }
        }
        return treeNodes;
    }

    public static <T extends TreeNodeElement> List<TreeNode<T>> buildByRecursion(List<T> elements) {
        return buildByRecursion(elements, null);
    }

    /**
     * 递归构建树(不推荐,时间复杂度高)
     */
    public static <T extends TreeNodeElement> List<TreeNode<T>> buildByRecursion(List<T> elements, String parentKey) {
        Objects.requireNonNull(elements, "elements must not be null!");
        List<TreeNode<T>> treeNodes = new ArrayList<>();
        for (T element : elements) {
            if (Objects.equals(element.getParentKey(), parentKey)) {
                TreeNode<T> treeNode = TreeNode.of(element);
                List<TreeNode<T>> children = buildByRecursion(elements, element.getKey());
                treeNode.addChildren(children);
                treeNodes.add(treeNode);
            }
        }
        return treeNodes;
    }
}