通過遞迴實現,單表父子關係資料 或者上下級關係資料的組合

勵志重寫JDK發表於2020-11-11
//測試程式碼
package com.xzff.web;

import com.alibaba.fastjson.JSON;

import java.util.ArrayList;
import java.util.List;

public class TreeNodeTest {

  public static void main(String[] args) {
    List<TreeNode> data = initData();
    TreeNodeUtils treeNodeUtils = new TreeNodeUtils(data);
    TreeNode root = treeNodeUtils.generateTree(0);
    System.out.println(JSON.toJSONString(root));
  }

  // 獲取資料  資料庫設計:一個頂級資料為root節點
  private static List<TreeNode> initData() {
    List<TreeNode> list = new ArrayList<>();
    list.add(new TreeNode(0, null, "大集團")); // 一個頂級資料為root節點
    list.add(new TreeNode(1, 0, "科技公司")); // 二級節點
    //    list.add(new TreeNode(2, 0, "文化傳媒公司")); // 二級節點
    //    list.add(new TreeNode(3, 0, "武昌辦事處")); // 二級節點
    //    list.add(new TreeNode(4, 0, "漢口辦事處")); // 二級節點
    list.add(new TreeNode(5, 1, "研發中心")); // 三級節點
    // list.add(new TreeNode(6, 1, "行政部")); // 三級節點
    //    list.add(new TreeNode(7, 5, "技術部")); // 四級節點
    //    list.add(new TreeNode(8, 5, "產品部")); // 四級節點
    //    list.add(new TreeNode(9, 5, "運維部")); // 四級節點
    //    list.add(new TreeNode(10, 2, "創作部")); // 三級節點
    //    list.add(new TreeNode(11, 2, "行政部")); // 三級節點
    return list;
  }
}

 

 

//測試實體類
package com.xzff.web;

import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Getter
@Setter
public class TreeNode {

  private Integer id;
  private Integer parentId;
  private String name;
  private List<TreeNode> childNodes;

  public TreeNode(Integer id, Integer parentId, String name) {
    this.id = id;
    this.parentId = parentId;
    this.name = name;
    this.childNodes = new ArrayList<>();
  }
}
//測試遞迴
package com.xzff.web;

import java.util.ArrayList;
import java.util.List;

public class TreeNodeUtils {

  private List<TreeNode> treeNodeList;

  public TreeNodeUtils(List<TreeNode> treeNodeList) {
    this.treeNodeList = treeNodeList;
  }

  /**
   * 生成以id為根節點的樹 傳入root根據節點id 遞迴演算法的第一步是分治,把複雜的大的問題,給拆分成一個一個小問題,直到不能再拆解,
   * 通過退出條件retrun,然後再從最小的問題開始解決,只到所有的子問題解決完畢,那麼 最終的大問題就迎刃而解。上面的列印資訊,符合棧資料結構的定義,
   * 先進後出,通過把所有的子問題壓棧之後,然後再一個個出棧,從最簡單的步驟計算,最終解決大問題,非常形象
   *
   * @param id
   * @return
   */
  public TreeNode generateTree(int id) {
    TreeNode root = getById(id); // 根據rootid  獲取到具體物件 實際上這裡可以排序 root放第一個,直接取出來
    List<TreeNode> childNodes = getChildrenById(id); // 先查詢二級節點集合
    if (childNodes != null && childNodes.size() > 0) {
      for (TreeNode node : childNodes) {
        // 將子節點作為根,查詢子節點的子節點
        // 通過debug看出,首先 將資料分而治之,從頂級,分解到最下面的子級,當沒有子級時,返回最下面的子級。
        TreeNode childRoot = generateTree(node.getId());
        // 返回子級以後,開始從下往上依次add :二級.add(三級),一級.add(二級),最終返回node頂級(List node二級( List node三級))
        root.getChildNodes().add(childRoot);
      }
    }

    return root;
  }

  /**
   * 根據id查詢節點
   *
   * @param id
   * @return
   */
  private TreeNode getById(int id) {
    for (TreeNode node : treeNodeList) {
      if (node.getId() == id) {
        return node;
      }
    }

    return null;
  }

  /**
   * 根據id查詢所有的子節點
   *
   * @param id
   * @return
   */
  private List getChildrenById(int id) {
    List<TreeNode> childNodes = new ArrayList<>();
    for (TreeNode node : treeNodeList) {
      if (node.getParentId() != null && node.getParentId() == id) {
        childNodes.add(node);
      }
    }

    return childNodes;
  }
}

測試程式碼是網上找的

測試資料:1級 包含二級 二級包含三級  資料各一條

經過斷點發現,首先傳入頂級id  獲取二級集合 ,遍歷時主要做的是:

1.遞迴檢視是否存在下一級

2.如果資料拆解,走到最後一級 ,沒有下一級的時候,if(list.size>0) ==false   

斷點走到return  ,return的node是最後一級資料,然後斷點走到 root.getChildNodes().add(childRoot); 從下往上依次add:二級.add(三級),一級.add(二級),最終返回node頂級(List node二級( List node三級))

 

總結:遞迴  先對資料進行從上而下的拆分,即找當前節點有沒有下一級,一直找的過程就是遞迴,什麼時候找到最後了,條件不成立了,會return ,從下往上依次返回資料,並進行最終要做的操作add 

相關文章