Java實現遞迴查詢樹結構

Javaの甘乃迪 發表於 2022-11-28
Java

        我們在實際開發中,肯定會用到樹結構,如部門樹、選單樹等等。Java後臺利用遞迴思路進行構建樹形結構資料,返回給前端,能以下拉選單等形式進行展示。今天,我們們就來說說怎麼樣將List集合轉換成TreeList

一、jar依賴

        為了簡化程式碼,引入Lombok的Jar包,可省略實體類set()、get()方法。

<dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
     <version>1.16.12</version>
</dependency>

二、樹節點資料類

/**
 *  TreeNode 樹節點 (定義每一個節點的資訊,即每一個節點對應一條資料資訊)
 */
@Data
public class TreeNode {
 
    /** 節點ID */
    private Integer id;
 
    /** 父節點ID:頂級節點為0 */
    private Integer parentId;
 
    /** 節點名稱 */
    private String label;
 
    /** 子節點 */
    private List<TreeNode> children;
 
    public TreeNode(Integer id, Integer parentId, String label) {
        this.id = id;
        this.parentId = parentId;
        this.label = label;
    }
}

三、構建樹形類

理解思路(個人):

1、首先獲取所有的根節點(頂級節點),即根節點的parentId = 0。

2、根據每一個根節點,與所有節點集合(資料)進行判斷,當前節點是否為其下的子節點。

3、若是,則遞迴呼叫構建樹形;若不是,則表明該節點不屬於其下子節點。

4、應繼續迴圈判斷節點父子關係,直到所有節點與根節點判斷完畢。

/**
 *  BuildTree 構建樹形結構
 */
public class TreeBuild {
    
    // 儲存參與構建樹形的所有資料(通常資料庫查詢結果)
    public List<TreeNode> nodeList = new ArrayList<>();
 
    /**
     *  構造方法
     *  @param nodeList 將資料集合賦值給nodeList,即所有資料作為所有節點。
     */
    public TreeBuild(List<TreeNode> nodeList){
        this.nodeList = nodeList;
    }
 
    /**
     *   獲取需構建的所有根節點(頂級節點) "0"
     *   @return 所有根節點List集合
     */
    public List<TreeNode> getRootNode(){
        // 儲存所有根節點(所有根節點的資料)
        List<TreeNode> rootNodeList = new ArrayList<>();
        // treeNode:查詢出的每一條資料(節點)
        for (TreeNode treeNode : nodeList){
            // 判斷當前節點是否為根節點,此處注意:若parentId型別是String,則要採用equals()方法判斷。
            if (0 == treeNode.getParentId()) {
                // 是,新增
                rootNodeList.add(treeNode);
            }
        }
        return rootNodeList;
    }
 
    /**
     *  根據每一個頂級節點(根節點)進行構建樹形結構
     *  @return  構建整棵樹
     */
    public List<TreeNode> buildTree(){
        // treeNodes:儲存一個頂級節點所構建出來的完整樹形
        List<TreeNode> treeNodes = new ArrayList<TreeNode>();
        // getRootNode():獲取所有的根節點
        for (TreeNode treeRootNode : getRootNode()) {
            // 將頂級節點進行構建子樹
            treeRootNode = buildChildTree(treeRootNode);
            // 完成一個頂級節點所構建的樹形,增加進來
            treeNodes.add(treeRootNode);
        }
        return treeNodes;
    }
 
    /**
     *  遞迴-----構建子樹形結構
     *  @param  pNode 根節點(頂級節點)
     *  @return 整棵樹
     */
    public TreeNode buildChildTree(TreeNode pNode){
        List<TreeNode> childTree = new ArrayList<TreeNode>();
        // nodeList:所有節點集合(所有資料)
        for (TreeNode treeNode : nodeList) {
            // 判斷當前節點的父節點ID是否等於根節點的ID,即當前節點為其下的子節點
            if (treeNode.getParentId().equals(pNode.getId())) {
                // 再遞迴進行判斷當前節點的情況,呼叫自身方法
                childTree.add(buildChildTree(treeNode));
            }
        }
        // for迴圈結束,即節點下沒有任何節點,樹形構建結束,設定樹結果
        pNode.setChildren(childTree);
        return pNode;
    }
 
}

四、測試案例

/**
 *  TreeController 樹控制層
 *  方式:傳遞所有資料集合作為引數,呼叫buildTree()構建樹形。
 */
@RestController
@RequestMapping("/tree")
public class TreeController {
 
    @GetMapping("/treeTest")
    public AjaxResult treeTest(){
 
        // 模擬測試資料(通常為資料庫的查詢結果)
        List<TreeNode> treeNodeList = new ArrayList<>();
        treeNodeList.add(new TreeNode(1,0,"頂級節點A"));
        treeNodeList.add(new TreeNode(2,0,"頂級節點B"));
        treeNodeList.add(new TreeNode(3,1,"父節點是A"));
        treeNodeList.add(new TreeNode(4,2,"父節點是B"));
        treeNodeList.add(new TreeNode(5,2,"父節點是B"));
        treeNodeList.add(new TreeNode(6,3,"父節點的ID是3"));
 
        // 建立樹形結構(資料集合作為引數)
        TreeBuild treeBuild = new TreeBuild(treeNodeList);
        // 原查詢結果轉換樹形結構
        treeNodeList = treeBuild.buildTree();
        // AjaxResult:個人封裝返回的結果體
        return AjaxResult.success("測試資料",treeNodeList);
    }
}

結果:

{
	"msg”:“ 測試資料”,
	"code": 200,
	"data": [
  		  {
			"id": 1,
			"parentId": 0,
			"label":"頂級節點A",
			"children": [
   		 {
					"id": 3,
    				"parentId": 1,
					"label":“ 父節點是A"
					"children": [
						"id": 6,
						"parentId": 3,
						"label":“ 父節點的ID是3
					}
				]
			}
		]
	}, 
	{
		"id": 2,
		"parentId": 0,
		"labe1":“ 頂級節點B",
		"children": [{
				"id": 4,
				"parentId": 2,
				"label":“ 父節點是B"
			},
			{
				"id": 5,
				"parentId": 2,
				"label":" 父節點是B
			}
		]
	}
]
}

本文介紹Java後臺構建樹形結構資料的設計思路及實現,如有不對可以或更好的方案,歡迎指出和討論。