Java 高效构建树形结构

Java 高效构建树形结构

构造树形结构通常使用递归遍历元素,构造元素的子集,直至子级全部构建完成,返回父级,最终完成树的构建,这种方法的时间复杂度基本上在 O ( N 2 ) O(N^2) O(N2),数据量比较大的时候性能大幅下降,耗时严重。通过不断实践与优化,得出一种可将构造树形结构的性能提升,时间复杂度能至 O ( N ) O(N) O(N)的方法。

方法说明:
  1. 将集合按父级id分组,得到父级id为key,子级元素集合为value的map;
  2. 遍历原集合,以元素id为key获取map中的子级集合,将子级集合放入父级元素中
  3. 返回最上层元素,即为树形结构数据
特点:

● 使用stream并行流,提高效率
● 通过对象地址引用实现父子级关联,即使父级先添加了子级,子级在添加孙子级,父子孙三级也全部都会关联

代码:
	import cn.hutool.core.collection.CollUtil;
	import cn.hutool.core.lang.Assert;

	/**
     * 构造数据树 O(N)
     *
     * @param list           原集合
     * @param mKey           父级被子集关联的字段,比如id
     * @param treeConnectKey 子集关联父级的字段,比如parentId
     * @param treeSortKey    同级菜单的排序字段,比如sort
     * @param consumer       添加子集的函数,如dto.setChild(list)
     * @param <M>
     * @return
     */
    public static <M> List<M> buildTree(List<M> list, Function<M, ?> mKey, Function<M, ?> treeConnectKey,
                                        Function<M, ? extends Comparable> treeSortKey, Consumers<M, M> consumer) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        Assert.notNull(mKey, "父级被子级关联的字段不能为空");
        Assert.notNull(treeConnectKey, "子级关联父级的字段不能为空");
        Assert.notNull(consumer, "消费函数不能为空");
        //线程安全类集合
        List<M> tree = Collections.synchronizedList(new ArrayList<>());
        //按上级id分组
        final Map<?, List<M>> collect = list.parallelStream().collect(Collectors.groupingBy(treeConnectKey));
        list.parallelStream().filter(m -> {
            final boolean b = (Long) treeConnectKey.apply(m) != 0L;
            if (!b) {
                tree.add(m);
            }
            return b;
        }).forEach(
                //通过对象地址引用实现父子级关联,即使父级先添加了子级,子级在添加孙子级,父子孙三级也全部都会关联
                m -> {
                    if (treeSortKey != null) {
                        consumer.accept(m, CollUtil.sort(collect.get(mKey.apply(m)), java.util.Comparator.comparing(treeSortKey)));
                    } else {
                        consumer.accept(m, collect.get(mKey.apply(m)));
                    }
                }
        );
        if (treeSortKey != null) {
            //排序
            tree.sort(java.util.Comparator.comparing(treeSortKey));
            return tree.parallelStream().peek(b -> consumer.accept(b, CollUtil.sort(collect.get(mKey.apply(b)), java.util.Comparator.comparing(treeSortKey)))).collect(Collectors.toList());
        } else {
            return tree.parallelStream().peek(b -> consumer.accept(b, collect.get(mKey.apply(b)))).collect(Collectors.toList());
        }
    }

    @FunctionalInterface
    public interface Consumers<M, N> {

        /**
         * 消费函数
         *
         * @param m
         * @param n
         */
        void accept(M m, List<N> n);
    }
}

调用:

import lombok.Getter;
import lombok.Setter;
import java.util.List;

/**
 * 部门
 */
@Getter
@Setter
public class DeptDTO {

    private Long id;

    /**
     * 上级部门
     */
    private Long parentId;

    /**
     * 部门名称
     */
    private String deptName;

    /**
     * 部门编码
     */
    private String deptCode;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 子部门
     */
    private List<DeptDTO> child;
}
//模拟原始数据
final List<DeptDTO> dtos = new ArrayList<>();
//获取树结构
List<DeptDTO> tree = TreeUtil.buildTree(dtos, DeptDTO::getId, DeptDTO::getParentId, DeptDTO::getCreateTime, DeptDTO::setChild);

表述不正确之处欢迎指正,欢迎留言分享效率更高的方法!

  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
构建树形结构,你可以使用Java中的树形数据结构,如树或二叉树。你可以将数据存储在节点中,然后使用递归方法来构建树形结构。 下面是一个简单的示例代码,用于构建一个二叉树并统计汇总: ```java class Node { int value; Node left; Node right; Node(int value) { this.value = value; left = null; right = null; } } class BinaryTree { Node root; BinaryTree() { root = null; } // 添加节点 void insert(int value) { root = insert(root, value); } Node insert(Node node, int value) { if (node == null) { node = new Node(value); return node; } if (value < node.value) { node.left = insert(node.left, value); } else if (value > node.value) { node.right = insert(node.right, value); } return node; } // 统计汇总 int sum(Node node) { if (node == null) { return 0; } return node.value + sum(node.left) + sum(node.right); } } public class TreeDemo { public static void main(String[] args) { BinaryTree tree = new BinaryTree(); // 添加节点 tree.insert(5); tree.insert(3); tree.insert(7); tree.insert(1); tree.insert(9); // 统计汇总 int total = tree.sum(tree.root); System.out.println("Total: " + total); } } ``` 在这个示例中,我们首先定义了一个`Node`类来表示树的节点,然后定义了一个`BinaryTree`类来表示二叉树,并提供了一个`insert`方法来添加节点。最后我们提供了一个`sum`方法来统计汇总,使用递归方法遍历整个树来计算节点值的总和。 在`main`方法中,我们创建了一个二叉树并添加了一些节点,最后调用`sum`方法来计算节点值的总和。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值