Java實現n級樹物件的封裝
阿新 • • 發佈:2018-12-25
專案開發中經常會遇到多叉樹的展示,最為常見的便是組織機構圖以及省市縣結構圖,
通常做法是接收伺服器端返回來的JSON格式的資料,動態生成樹形選單節點。
動態生成樹有兩種思路:
- 非同步載入節點,適用於節點數量很多的結構,通過zTree等外掛封裝的方法,傳入指定的節點ID查詢出當前節點下的子節點資訊。
- 一次性生成全部樹節點,適用於小資料量的結構。
今天的筆記記錄的是第二種思路的實現方式,共兩種
第一種為最常規的做法,將節點以節點編號為Key存入散列表,隨後遍歷散列表通過Key值與節點的parentId對應關係再構造出多叉樹:
public class InfiniteLevelTreeUtil {
public static List<Node> getInfiniteLevelTree() {
// 讀取層次資料結果集列表
List<Node> dataList = dao.getNodes();
// 將Node存入散列表
Map<String, Node> nodeMap = dataList.stream().collect(Collectors.toMap(Node::getId, node -> node));
// 根節點
List<Node> root = new ArrayList<>();
// 構造無序的多叉樹
for(Map.Entry<String, Node> entry: nodeMap.entrySet()) {
Node node = entry.getValue();
if (node.getParentId().equals("-1")) {
root.add(node);
} else {
nodeMap.get(node.getParentId()).addChild(node);
}
}
return root;
}
}
// 節點Bean
public class Node {
private String id;
private String name;
private String parentId;
private int order;
private Children children = new Children();
// ...get set 方法,構造方法
// 兄弟節點排序
public void sortChildren() {
if (children != null && children.getSize() != 0) {
children.sortChildren();
}
}
// 新增孩子節點
public void addChild(Node node) {
this.children.addChild(node);
}
}
// 子節點Bean
public class Children {
private List<Node> list = new ArrayList<>();
// ...get set 方法,構造方法
public int getSize() {
return list.size();
}
public void addChild(Node node) {
list.add(node);
}
// 孩子節點排序
public void sortChildren() {
Collections.sort(list, new NodeOrderComparator());
for (Iterator<Node> it = list.iterator(); it.hasNext();) {
it.next().sortChildren();
}
}
}
// 節點排序Comparator
public class NodeOrderComparator implements Comparator<Node>{
// 按照節點排序值進行排序
public int compare(Node n1, Node n2) {
return (n1.getOrder() < n2.getOrder() ? -1 : (n1.getOrder() == n2.getOrder() ? 0 : 1));
}
}
第二種做法使用了遞迴,以parentId = '-1'
(根節點)作為遞迴方法的入口,構造多叉樹。
public class InfiniteLevelTreeUtil {
// 入口方法
public List<Node> getInfiniteLevelTree(List<Node> nodeList) {
List<Node> list = new ArrayList<>();
// 遍歷節點列表
for (Node node : nodeList) {
if (node.getParentId().equals("-1")) {
// parentID為-1(根節點)作為入口
node.setChildren(getChildrenNode(node.getId(), nodeList));
list.add(node);
}
}
// 排序
list.sort(new NodeOrderComparator());
return list;
}
// 獲取子節點的遞迴方法
public List<Node> getChildrenNode(String id, List<Node> nodeList) {
List<Node> lists = new ArrayList<>();
for (Node node : nodeList) {
if (node.getParentId().equals(id)) {
// 遞迴獲取子節點
node.setChildren(getChildrenNode(node.getId(), nodeList));
lists.add(node);
}
}
// 排序
lists.sort(new NodeOrderComparator());
return lists;
}
}
// 節點Bean
public class Node {
private String id;
private String name;
private String parentId;
private int order;
private List<Node> children = new ArrayList<>();
// ...get set 方法,構造方法
}
// 節點排序Comparator
public class NodeOrderComparator implements Comparator<Node>{
// 按照節點排序值進行排序
public int compare(Node n1, Node n2) {
return (n1.getOrder() < n2.getOrder() ? -1 : (n1.getOrder() == n2.getOrder() ? 0 : 1));
}
}
測試:
節點列表如下(id,name,pid,order):
Node n1 = new Node("0", "根節點", "-1", 0);
Node n2 = new Node("01", "一級子節點", "0", 0);
Node n3 = new Node("011", "二級子節點1", "01", 3);
Node n4 = new Node("012", "二級子節點2", "01", 2);
Node n5 = new Node("013", "二級子節點3", "01", 1);
Node n6 = new Node("0131", "三級子節點1", "013", 1);
Node n7 = new Node("0132", "三級子節點2", "013", 1);
執行方法後得到的樹結構的JSON串如下:
{
'id': '0',
'name': '根節點',
'children': [{
'id': '01',
'name': '一級子節點',
'children': [
{
'id': '011',
'name': '二級子節點1',
'children':[]
},
{
'id': '012',
'name': '二級子節點2',
'children': []
},
{
'id': '013',
'name': '二級子節點3',
'children': [
{
'id': '0131',
'name': '三級子節點1'
},
{
'id': '01312',
'name': '三級子節點2'
}
]
}
]
}]
}
以上,實現了無線級樹節點的構造