Java 高效构建树形结构
构造树形结构通常使用递归遍历元素,构造元素的子集,直至子级全部构建完成,返回父级,最终完成树的构建,这种方法的时间复杂度基本上在 O ( N 2 ) O(N^2) O(N2),数据量比较大的时候性能大幅下降,耗时严重。通过不断实践与优化,得出一种可将构造树形结构的性能提升,时间复杂度能至 O ( N ) O(N) O(N)的方法。
方法说明:
- 将集合按父级id分组,得到父级id为key,子级元素集合为value的map;
- 遍历原集合,以元素id为key获取map中的子级集合,将子级集合放入父级元素中
- 返回最上层元素,即为树形结构数据
特点:
● 使用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);
}
}
调用:文章来源:https://www.toymoban.com/news/detail-561712.html
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);
表述不正确之处欢迎指正,欢迎留言分享效率更高的方法!文章来源地址https://www.toymoban.com/news/detail-561712.html
到了这里,关于Java 高效构建树形结构的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!