最近在写的业务中,涉及了很多需求,需要将 sql 中的数据查询,然后根据 parentId 构建成树状结构。在实现这一需求的过程中,没有找到太好的解决方法,还在网站中提问,也暂时没有获得更好的回答结果。因此写下这篇文章,也希望能有大佬提供更好的思路,在此感谢。
提问地址:https://ask.csdn.net/questions/7953659?spm=1001.2014.3001.5501
实现一:遍历
最容易理解的方式,两个 for 循环,直接找 parentId = uid 的,加入子节点。
for(i : 1 to n) {
for (j : 1 to n) {
if (modeli.getUid().equals(modelj.getParentId())) {
modeli.addChild(modelj);
}
}
}
时间复杂度 O(n^2),空间复杂度 O(1)
实现二:bfs遍历
实现二是对实现一的优化,将已经遍历过,成为父节点的节点,从待遍历队列中移除,从而达到降低时间复杂度的效果。
queue<model> solvedQueue;
queue<model> unsolvedQueue = new LinkedList<>();
List<model> rootList = new ArrayList<>();
// 预处理,将根节点提出
for(i : 1 to n) {
if (modelList.get(i).getParentId() == null) {
rootList.add(modeli);
} else {
unsolvedQueue.add(modeli);
}
}
solvedQueue = new LinkedList(rootList);
while (!solvedQueue.isEmpty() && !unsolvedQueue.isEmpty()) {
model = solvedQueue.poll();
int length = unsolvedQueue.size();
while((length--) > 0) {
unsolvedModel = unsolvedQueue.poll();
if (unsolvedModel.getParentId().equals(model.getUid)) {
model.addChild(unsolvedModel);
solvedQueue.add(unsolvedModel);
} else {
unsolvedQueue.add(unsolvedModel);
}
}
}
return rootList;
时间复杂度O(nlogn)?,空间复杂度O(n)
实现三:递归
找到根节点之后,递归每一层,获取子节点并存入,然后重复上述过程。
List<model> rootList = new ArrayList<>();
for(i : 1 to n) {
if (model.getParentId() == null) {
rootList.add(model);
buildTree(model, modelList);
}
}
void buildTree(root, modelList) {
if (root == null) {
return;
}
for (i : 1 to n) {
if (model.getParentId().equals(root.getUid)) {
buildTree(model, modelList);
root.addChild(model);
}
}
}
时间复杂度O(n^n),空间复杂度O(1)
实现四:Map 偷渡
这种用于数据量较低的时候,可以简单实现。将 uid-model 保存为 map 键值对,然后只需要遍历一遍 map 就可以了。
Map<String, model> modelMap = new HashMap<>();
List<model> rootList;
for (i : 1 to n) {
modelMap.put(model.getUid(), model);
if (model.getParentId() == null) {
rootList.add(model);
}
}
for (model : modelMap.values()) {
if (modelMap.exist(model.getParentId()) {
modelMap.get(model.getParentId()).addChild(model);
}
}
return rootList;
时间复杂度O(n),空间复杂度 O(n)