本文記錄List結構數據組裝成樹結構實現.
使用場景
通過查詢數據庫中具有父子關係的結構數據,將獲得的List數據轉換爲Tree結構的數據,一般用於前端多級樹展示
技術點
- 遞歸
- 雙層for循環
- 高速緩存Map
效果展示
[{
"id": "1",
"name": "廣州",
"parentId": "0",
"children": [{
"id": "3",
"name": "天河區",
"parentId": "1",
"children": [{
"id": "6",
"name": "石牌",
"parentId": "3",
"children": [{
"id": "7",
"name": "百腦匯",
"parentId": "6"
}]
}]
}, {
"id": "4",
"name": "越秀區",
"parentId": "1"
}, {
"id": "5",
"name": "黃埔區",
"parentId": "1"
}]
}, {
"id": "2",
"name": "深圳",
"parentId": "0",
"children": [{
"id": "8",
"name": "南山區",
"parentId": "2",
"children": [{
"id": "10",
"name": "科技園",
"parentId": "8"
}]
}, {
"id": "9",
"name": "寶安區",
"parentId": "2"
}]
}]
實現代碼
樹節點定義:
import com.alibaba.fastjson.annotation.JSONType;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* TODO 樹節點
*
* @date 2019/8/19 17:54
**/
@Data
@JSONType(orders = {"id","name","parentId","children"})
public class TreeNode implements Serializable{
private String id;
private String parentId;
private String name;
private List<TreeNode> children;
public TreeNode(String id, String name, String parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
public TreeNode(String id, String name, TreeNode parent) {
this.id = id;
this.name = name;
this.parentId = parent.getId();
}
public TreeNode(TreeNode node) {
this.id = node.getId();
this.name = node.getName();
this.parentId = node.getParentId();
}
}
樹組裝類:
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* TODO 樹構造器
*
* @date 2019/8/19 17:55
**/
public class TreeBuilder {
/**
* TODO 雙層循環實現建樹,對傳入的樹節點列表無排序要求
* @param treeNodes 傳入的樹節點列表
* @return
*/
public static List<TreeNode> bulidByLoop(List<TreeNode> treeNodes) {
List<TreeNode> trees = new ArrayList<TreeNode>();
for (TreeNode treeNode : treeNodes) {
/*
* 根節點的父Id爲0,且不要求僅有唯一的根
*/
if ("0".equals(treeNode.getParentId())) {
trees.add(treeNode);
}
for (TreeNode it : treeNodes) {
if (it.getParentId() == treeNode.getId()) {
if (treeNode.getChildren() == null) {
treeNode.setChildren(new ArrayList<TreeNode>());
}
treeNode.getChildren().add(it);
}
}
}
return trees;
}
/**
* TODO 使用遞歸方法建樹,對傳入的樹節點列表無排序要求
* @param treeNodes
* @return
*/
public static List<TreeNode> buildByRecursive(List<TreeNode> treeNodes) {
List<TreeNode> trees = new ArrayList<TreeNode>();
for (TreeNode treeNode : treeNodes) {
// 根節點的父Id爲0,且不要求僅有唯一的根
if ("0".equals(treeNode.getParentId())) {
trees.add(findChildren(treeNode,treeNodes));
}
}
return trees;
}
/**
* TODO 遞歸查找子節點
* @param treeNodes
* @return
*/
public static TreeNode findChildren(TreeNode treeNode,List<TreeNode> treeNodes) {
for (TreeNode it : treeNodes) {
if(treeNode.getId().equals(it.getParentId())) {
if (treeNode.getChildren() == null) {
treeNode.setChildren(new ArrayList<TreeNode>());
}
treeNode.getChildren().add(findChildren(it,treeNodes));
}
}
return treeNode;
}
/**
* TODO 通過Map緩存生成樹
* @param dataList 經過排序的集合,要求父節點必須位於集合第一個元素,且僅能存在唯一的根節點
* @return tree.TreeNode
**/
public static TreeNode bulidByMapLink(List<TreeNode> dataList) {
if (null == dataList || 0 == dataList.size()) {
return null;
}
// 節點緩存
Map<String, TreeNode> linkTree = new HashMap<String, TreeNode>();
TreeNode temp = new TreeNode(dataList.get(0));
// 緩存樹結構
linkTree.put(temp.getId(), temp);
// 遍歷數據除首條外的數據,建立節點關聯關係
for (int i = 1; i < dataList.size(); i++) {
TreeNode node = new TreeNode(dataList.get(i));
if (null != linkTree.get(dataList.get(i).getParentId())) {
// 緩存中已存在相關父節點,子節點
if (null == linkTree.get(dataList.get(i).getParentId()).getChildren()) {
// 緩存中子節點不存在
linkTree.get(dataList.get(i).getParentId()).setChildren(new ArrayList<TreeNode>());
}
linkTree.get(dataList.get(i).getParentId()).getChildren().add(node);
}
linkTree.put(node.getId(), node);
}
TreeNode reTree = linkTree.get(temp.getId());
linkTree.clear();
return reTree;
}
/**
* TODO 爲雙層循環,遞歸方法實現建樹組裝集合
* @param
* @return java.util.List<tree.TreeNode>
* @date 2019/8/20 10:44
**/
public static List<TreeNode> initList(){
TreeNode treeNode1 = new TreeNode("1","廣州","0");
TreeNode treeNode2 = new TreeNode("2","深圳","0");
TreeNode treeNode3 = new TreeNode("3","天河區",treeNode1);
TreeNode treeNode4 = new TreeNode("4","越秀區",treeNode1);
TreeNode treeNode5 = new TreeNode("5","黃埔區",treeNode1);
TreeNode treeNode6 = new TreeNode("6","石牌",treeNode3);
TreeNode treeNode7 = new TreeNode("7","百腦匯",treeNode6);
TreeNode treeNode8 = new TreeNode("8","南山區",treeNode2);
TreeNode treeNode9 = new TreeNode("9","寶安區",treeNode2);
TreeNode treeNode10 = new TreeNode("10","科技園",treeNode8);
List<TreeNode> list = new ArrayList<TreeNode>();
list.add(treeNode1);
list.add(treeNode2);
list.add(treeNode3);
list.add(treeNode4);
list.add(treeNode5);
list.add(treeNode6);
list.add(treeNode7);
list.add(treeNode8);
list.add(treeNode9);
list.add(treeNode10);
return list;
}
/**
* TODO 爲通過Map緩存實現建樹組裝集合
* @param
* @return java.util.List<tree.TreeNode>
* @date 2019/8/20 10:45
**/
public static List<TreeNode> initListByMapLink(){
TreeNode treeNode0_t = new TreeNode("0","中國","-1");
TreeNode treeNode1_t = new TreeNode("1","廣州",treeNode0_t);
TreeNode treeNode2_t = new TreeNode("2","深圳",treeNode0_t);
TreeNode treeNode3_t = new TreeNode("3","天河區",treeNode1_t);
TreeNode treeNode4_t = new TreeNode("4","越秀區",treeNode1_t);
TreeNode treeNode5_t = new TreeNode("5","黃埔區",treeNode1_t);
TreeNode treeNode6_t = new TreeNode("6","石牌",treeNode3_t);
TreeNode treeNode7_t = new TreeNode("7","百腦匯",treeNode6_t);
TreeNode treeNode8_t = new TreeNode("8","南山區",treeNode2_t);
TreeNode treeNode9_t = new TreeNode("9","寶安區",treeNode2_t);
TreeNode treeNode10_t = new TreeNode("10","科技園",treeNode8_t);
List<TreeNode> list_t = new ArrayList<TreeNode>();
list_t.add(treeNode0_t);
list_t.add(treeNode1_t);
list_t.add(treeNode2_t);
list_t.add(treeNode3_t);
list_t.add(treeNode4_t);
list_t.add(treeNode5_t);
list_t.add(treeNode6_t);
list_t.add(treeNode7_t);
list_t.add(treeNode8_t);
list_t.add(treeNode9_t);
list_t.add(treeNode10_t);
return list_t;
}
@Test
public void testBulidByLoop(){
List<TreeNode> treeNodes = initList();
List<TreeNode> trees_0 = TreeBuilder.bulidByLoop(treeNodes);
// 指定Json轉換時保持Key順序,Key順序由@JSONType(orders)指定
System.out.println("trees[0]:"+ JSONObject.toJSONString(trees_0, SerializerFeature.SortField));
}
@Test
public void testBulidByRecursive(){
List<TreeNode> treeNodes = initList();
List<TreeNode> trees_1 = TreeBuilder.buildByRecursive(treeNodes);
System.out.println("trees[1]:"+ JSONObject.toJSONString(trees_1, SerializerFeature.SortField));
}
@Test
public void testBulidByMapLink(){
List<TreeNode> treeNodes = initListByMapLink();
TreeNode trees_2 = TreeBuilder.bulidByMapLink(treeNodes);
System.out.println("trees[2]:"+ JSONObject.toJSONString(trees_2, SerializerFeature.SortField));
}
}