1. 程式人生 > >Java實現n級樹物件的封裝

Java實現n級樹物件的封裝

專案開發中經常會遇到多叉樹的展示,最為常見的便是組織機構圖以及省市縣結構圖,
通常做法是接收伺服器端返回來的JSON格式的資料,動態生成樹形選單節點。
動態生成樹有兩種思路:

  1. 非同步載入節點,適用於節點數量很多的結構,通過zTree等外掛封裝的方法,傳入指定的節點ID查詢出當前節點下的子節點資訊。
  2. 一次性生成全部樹節點,適用於小資料量的結構。

今天的筆記記錄的是第二種思路的實現方式,共兩種

第一種為最常規的做法,將節點以節點編號為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'
                    }
                ] 
            }
        ]  
    }]  
}

以上,實現了無線級樹節點的構造

趁著年輕,好好奮鬥一把