树
相信大家对树结构都不陌生。这里不做冗余介绍,如果有不懂的请自行google
学习。这里只介绍我们在实际中会经常用到的组装树的简单算法,仅供参考,欢迎讨论。
JAVA实现
基本对象
public class Node implements Serializable {
private long id;
private Long parentId;
private List<Node> childs;
public Node(long id, Long parentId, List<Node> childs) {
this.id = id;
this.parentId = parentId;
this.childs = childs;
}
public Node(long id, Long parentId) {
this.id = id;
this.parentId = parentId;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public List<Node> getChilds() {
return childs;
}
public void setChilds(List<Node> childs) {
this.childs = childs;
}
public void addChild(Node node){
if(childs == null){
childs = new ArrayList<>();
}
childs.add(node);
}
}
第一种
这种也是最常用的方式:
private static List<Node> getTree1(List<Node> nodes) {
List<Node> res = new ArrayList<>();
Map<Long, Node> catalogMap = new HashMap<>();
for (Node c : nodes) {
if (c.getParentId() == null) {
res.add(c);
}
catalogMap.put(c.getId(), c);
}
for (Map.Entry entry : catalogMap.entrySet()) {
Node parent = catalogMap.get(entry.getKey());
if (parent != null) {
parent.addChild((Node) entry.getValue());
} else {
res.add((Node) entry.getValue());
}
}
return res;
}
第二种
以空间换时间,增加一个记录父节点的parentMap,二次循环遍历这个parentMap,来减少遍历次数。不过JVM维护parentMap本身也需要耗费时间,这种方式要分情况使用。
private static List<Node> getTree2(List<Node> nodes) {
List<Node> res = new ArrayList<>();
Map<Long, List<Node>> parentMap = new HashMap<>();
Map<Long, Node> catalogMap = new HashMap<>();
for (Node c : nodes) {
if (c.getParentId() == null) {
res.add(c);
} else {
parentMap.compute(c.getParentId(), new BiFunction<Long, List<Node>, List<Node>>() {
@Override
public List<Node> apply(Long aLong, List<Node> nodes) {
if (nodes == null) {
nodes = new ArrayList<>();
}
nodes.add(c);
return nodes;
}
});
}
catalogMap.put(c.getId(), c);
}
for (Map.Entry entry : parentMap.entrySet()) {
Node parent = catalogMap.get(entry.getKey());
if (parent != null) {
parent.setChilds((List<Node>) entry.getValue());
} else {
res.addAll((Collection<? extends Node>) entry.getValue());
}
}
return res;
}
执行时间
经测试,在list大小小于等于50W时,第一种快。在list大小大于50W时,第二种快。