Java構建樹結構的公共方法

来源:https://www.cnblogs.com/kakarotto-chen/archive/2023/04/12/17310304.html
-Advertisement-
Play Games

一、前提 pId需要傳入用來確認第一級的父節點,而且pId可以為null。 樹實體類必須實現:TreeNode介面 MyTreeVo必須有這三個屬性:id、pId、children 可以根據不同需求,配置TreeNode和MyTreeVo中固定的屬性 二、代碼 定義TreeNode介面 public ...


一、前提

  • pId需要傳入用來確認第一級的父節點,而且pId可以為null。
  • 樹實體類必須實現:TreeNode介面
  • MyTreeVo必須有這三個屬性:id、pId、children
  • 可以根據不同需求,配置TreeNode和MyTreeVo中固定的屬性

二、代碼

  • 定義TreeNode介面
public interface TreeNode {
    String getId();
    String getpId();
    List getChildren();
}

  • 需要將pId作為參數傳入,在方法中添加一個pId參數,用於確認第一級的父節點。
    -- 這個示例代碼中,buildTree方法接收兩個參數,一個是泛型類型的參數List,另一個是pId,用於確認第一級的父節點。在找到所有的根節點後,我們需要對每個根節點調用buildChildren方法,遞歸構建子節點。
    -- 以便支持傳入的pId作為頂級節點
public class TreeBuilder {
    /**
     * @param nodes 需要構建的nodes,不要繼承 TreeNode,且需要有 TreeNode 下的三個方法
     * @param pId 父id。為null則是所有pid為null的是頂級節點;不為null,則是從給的pId往下查詢並構建樹
     **/
    public static <T extends TreeNode> List<T> buildTree(List<T> nodes, String pId) {
        List<T> roots = new ArrayList<>();
        for (T node : nodes) {
            if (node.getId().equals(pId) || (node.getParentId() == null && (pId == null || pId.equals(node.getId())))) {
                roots.add(node);
            }
        }
        for (T root : roots) {
            buildChildren(root, nodes);
        }
        return roots;
    }

    private static <T extends TreeNode> void buildChildren(T node, List<T> nodes) {
        for (T child : nodes) {
            if (child.getParentId() != null && child.getParentId().equals(node.getId())) {
                node.getChildren().add(child);
                buildChildren(child, nodes);
            }
        }
    }
}

  • 構建到幾級
    -- 如果再增加一個參數,構建到樹的第幾層該如何實現?
    -- 根據需求,如果增加一個參數來控制構建到樹的第幾層,可以在buildChildren方法中添加一個level參數,用於記錄當前節點的層數。在遞歸構建子節點時,如果當前節點的層數小於指定的層數,則繼續遞歸構建子節點,否則停止遞歸。以下是修改後的Java示例代碼:
public class TreeBuilder {
     
     /**
      * @param level 級別 從1開始。1是最頂層
      **/
    public static <T extends TreeNode> List<T> buildTree(List<T> nodes, String pId, int level) {
        List<T> roots = new ArrayList<>();
        for (T node : nodes) {
            if (node.getId().equals(pId) || (node.getParentId() == null && (pId == null || pId.equals(node.getId())))) {
                roots.add(node);
            }
        }
        for (T root : roots) {
            buildChildren(root, nodes, level, 1);
        }
        return roots;
    }

    private static <T extends TreeNode> void buildChildren(T node, List<T> nodes, int level, int currentLevel) {
        if (currentLevel >= level) {
            return;
        }
        for (T child : nodes) {
            if (child.getParentId() != null && child.getParentId().equals(node.getId())) {
                if (node.getChildren() == null) {
                    node.setChildren(new ArrayList<>());
                }
                node.getChildren().add(child);
                buildChildren(child, nodes, level, currentLevel + 1);
            }
        }
    }
}


三、使用

1、實現TreeNode介面

public class MyTreeVo implements TreeNode {

    /**
     * 主鍵
     */
    private String id;

    /**
     * 父節點ID
     */
    private String pId;

    /**
     * 子級
     */
    private List<MyTreeVo> children = Lists.newArrayList();

    //其他屬性……

    public List<MyTreeVo> getChildren() {
        return children;
    }

    public String getId() {
        return id;
    }

    public String getpId() {
        return pId;
    }

    //其他屬性的getter、setter……

2、使用

-- pId可以傳入null,也可以傳入需要從哪個節點(X)開始構造的 X的id
-- pId比如可以傳入3、樣例中的 “二、噢噢噢噢”的id=“e6ee51485389495cb923a122be800012”。然後構建出來的,就是“二、噢噢噢噢”的下級樹

List<MyTreeVo> tree = TreeUtilQz.buildTree(vos,null);
//tree就是構建好的樹結構數據

3、樣例

{
    "data": [
        {
            "id": "e6ee51485389495cb923a122be800011",
            "pId": "",
            "name": "一、鋼管鋼管",
            "children": [
                {
                    "id": "e6ee51485389495cb923a122be800014",
                    "pId": "e6ee51485389495cb923a122be800011",
                    "name": "(二)嘎嘎嘎嘎嘎",
                    "children": []
                },
                {
                    "id": "e6ee51485389495cb923a122be800013",
                    "pId": "e6ee51485389495cb923a122be800011",
                    "name": "(一)頂頂頂頂",
                    "children": []
                }
            ]
        },
        {
            "id": "e6ee51485389495cb923a122be800012",
            "pId": "",
            "name": "二、噢噢噢噢",
            "children": [
                {
                    "id": "e6ee51485389495cb923a122be800015",
                    "pId": "e6ee51485389495cb923a122be800012",
                    "name": "二的下級",
                    "children": [
                        {
                            "id": "e6ee51485389495cb923a122be800016",
                            "pId": "e6ee51485389495cb923a122be800015",
                            "name": "二的下級的下級",
                            "children": []
                        }
                    ]
                }
            ]
        }
    ]
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文已經收錄到Github倉庫,該倉庫包含電腦基礎、Java基礎、多線程、JVM、資料庫、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分散式、微服務、設計模式、架構、校招社招分享等核心知識點,歡迎star~ Github地址 如果訪問不了Github,可以訪 ...
  • :pushpin: 新建文件 //這是要操作的文件名稱 string str_filename = "E:/data/t/haha.txt"; //創建一個流對象 o 就是從這個流對象出去, 出到哪裡, 當然是我們要建立的文件 ofstream ofs; //out會覆蓋 ofs.open(str_ ...
  • 列表(list)與元組(tuple) 列表的格式 [數據1,數據2,數據3,數據4,......] 列表可以存儲多個數據,數據之間的逗號以英文分割而且可以數據是不同類型的數據,列表是可變數據類型。 空列表 list_data = [] 或者 list_data = list() 列表的創建 # 使用 ...
  • 修改的概念:對於硬碟上數據的修改, 根本沒有改的操作, 只有覆蓋操作 修改的流程:文件的修改都是數據載入到記憶體中, 在記憶體中修改完再覆蓋入硬碟 一.修改方式一 1.修改過程 先以 r 模式打開源文件,將源文件內容全部讀入記憶體 然後在記憶體中完成修改 再以 w 模式打開源文件,將修改後的內容覆蓋入源文件 ...
  • 說明 使用 VLD 記憶體泄漏檢測工具輔助開發時整理的學習筆記。本篇介紹如何在 Release 模式下使用 VLD。同系列文章目錄可見 《記憶體泄漏檢測工具》目錄 1. 思路概述 要在 RELEASE 模式下使用 VLD,必須在包含頭文件 vld.h 前預先定義 VLD_FORCE_ENABLE 巨集(參 ...
  • 拋硬幣實驗 random 模塊 import random random.randint(a, b) 返回一個隨機整數 N,範圍是:a <= N <= b random.choice("ilovefishc") 從 "ilovefishc" 這個字元串中隨機選出一個字元。 編寫一個雙色球的開獎模擬程 ...
  • 結構體 ​ 結構體是一種聚合的數據類型,是由零個或多個任意類型的值聚合成的實體。每個值稱為結構體的成員 結構體聲明 type + 結構體名 + struct + {成員列表} ​ :star:如果結構體成員名字是以大寫字母開頭的,那麼該成員就是導出的。這是Go語言導出規則決 定的。一個結構體可能同時 ...
  • PostgreSQL 備忘清單 PostgreSQL是一種特性非常齊全的自由軟體的對象-關係型資料庫管理系統(ORDBMS),是以加州大學電腦系開發的POSTGRES,4.2版本為基礎的對象關係型資料庫管理系統。POSTGRES的許多領先概念只是在比較遲的時候才出現在商業網站資料庫中。Postgr ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...