1. 程式人生 > >基於遞迴演算法,樹形結構資料下業務場景,封裝解決方法

基於遞迴演算法,樹形結構資料下業務場景,封裝解決方法

本文原始碼:GitHub·點這裡 || GitEE·點這裡

一、遞迴演算法

1、概念簡介

遞迴演算法的核心思想是通過將問題重複分解為同類的或其子問題的方式,從而可以使用統一的解決方式。很多程式語言支援方法或函式自我呼叫,簡單的說,就是在函式或方法體內,自身可以再次呼叫自身的方法結構。

2、基礎案例

這裡通過遞迴的方式,計算階乘、求和等相關邏輯。

public class Demo01 {
    public static void main(String[] args) {
        int result1 = factorial(5);
        System.out.println(result1);
        int result2 = sum(100) ;
        System.out.println(result2);
    }
    // 遞迴階乘
    private static int factorial (int n){
        if(n <= 1){
            return n ;
        }else{
            return n*factorial(n-1);
        }
    }
    // 遞迴求和
    private static int sum (int f){
        if(f <= 1){
            return f ;
        }else{
            return f + sum(f-1);
        }
    }
}

3、注意事項

  • 使用方法

使用遞迴的時候,要明確業務邏輯可以分解為重複相同的問題,且要清楚的知道遞迴的結束條件,不然很容易出現死迴圈。

  • 優缺點描述

遞迴演算法的程式碼比較簡潔,可讀性較好;但是在實際的業務處理中會出現多次的重複呼叫,如果處理不好,很容易出現StackOverflowError報錯。

二、樹狀結構

1、概念描述

樹形結構是一層次的巢狀結構。一個樹形結構的外層和內層有相似的結構,所以這種結構多可以遞迴的表示。

2、圖解和定義

  • 根節點

樹的根源,沒有父節點的節點,如上圖A節點。

  • 兄弟節點

擁有同一父節點的子節點。如圖B與C與D節點。

  • 葉子節點

沒有子節點的節點。如圖E和F等節點。

  • 分支度

指一個節點有幾個子節點。 如:A為3、B為2。

  • 節點深度

指從該節點到某一節點的最長路徑。如圖A為2、B為1。

三、應用場景

1、場景描述

基於遞迴演算法下,處理很多樹形結構的業務資料。常見的業務場景如下:

  • 省市區三級聯動查詢 ;
  • 系統模組、選單、按鈕的授權 ;
  • 常見的業務資料分類:商品分類等 ;
  • 常見各種行業分類細化 ;

2、特殊場景

在管理系統中,對系統模組、選單、按鈕授權操作時候可能會出現如下情況。

假如系統管理員的許可權如圖所示,但是給到運營人員的許可權如下,需要把3號選單和5號選單設定為同級別,這時候基本的處理手法就是把3號選單父級ID作為3號選單和下屬功能的許可權的根節點,這裡把這裡當成兩顆樹進行分別處理,最後合併資料就好。必要時按照配上節點編碼,例如NODE01,NODE0101,NODE0102等方式,這裡針對這個場景描述,就是希望在處理類似業務時候,思路要開闊,不必拘泥於單個樹形結構。業務很多時候都是出人意料甚至是令人生厭,不過這確實就是生活

3、工具類封裝

這裡展示一個樹形結構常用的幾個封裝方法,例如建立樹形結構,遍歷,判斷等。

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

public class ThreeUtil {
    /**
     * 遞迴建立樹形結構
     */
    private static List<ThreeNode> getTree(List<ThreeNode> nodeList, Integer parentId) {
        List<ThreeNode> threeNodeList = new ArrayList<>() ;
        for (ThreeNode entity : nodeList) {
            Integer nodeId = entity.getId() ;
            Integer nodeParentId = entity.getParentId() ;
            if (parentId.intValue() == nodeParentId.intValue()) {
                List<ThreeNode> childList = getTree(nodeList,nodeId) ;
                if (childList != null && childList.size()>0){
                    entity.setChildNode(childList);
                    entity.setChildNodeSize(childList.size());
                }
                threeNodeList.add(entity) ;
            }
        }
        return threeNodeList ;
    }

    /**
     * 獲取指定子節點
     */
    private static List<ThreeNode> getChildTree (Integer id,List<ThreeNode> nodeList){
        List<ThreeNode> resultList = new ArrayList<>();
        for (ThreeNode entity : nodeList) {
            if (entity.getParentId().intValue() == id) {
                List<ThreeNode> childList = getChildTree(entity.getId(),nodeList) ;
                entity.setChildNode(childList);
                entity.setChildNodeSize(childList.size());
                resultList.add(entity) ;
            }
        }
        return resultList ;
    }

    /**
     * 遍歷樹形結構
     */
    private static transient List<Integer> treeIdList = new ArrayList<>() ;
    private static List<Integer> getTreeInfo (List<ThreeNode> treeList){
        for (ThreeNode entity : treeList) {
            if (entity.getChildNodeSize()!=null && entity.getChildNodeSize()>0){
                getTreeInfo(entity.getChildNode());
            }
            treeIdList.add(entity.getId());
        }
        return treeIdList ;
    }

    /**
     * 判斷節是否是葉子節點
     */
    private static boolean hasChildNode (Integer id,List<ThreeNode> nodeList){
        for (ThreeNode entity:nodeList){
            if (entity.getParentId().intValue() == id){
                return true ;
            }
        }
        return false ;
    }

    public static void main(String[] args) {
        List<ThreeNode> threeNodeList = new ArrayList<>() ;
        threeNodeList.add(new ThreeNode(1,"節點A",0)) ;
        threeNodeList.add(new ThreeNode(2,"節點B",1)) ;
        threeNodeList.add(new ThreeNode(3,"節點C",1)) ;
        threeNodeList.add(new ThreeNode(4,"節點D",1)) ;
        threeNodeList.add(new ThreeNode(5,"節點E",2)) ;
        threeNodeList.add(new ThreeNode(6,"節點F",2)) ;
        // 測試1
        List<ThreeNode> getTree = getTree(threeNodeList,0) ;
        System.out.println(getTree);
        // 測試2
        // List<ThreeNode> getChildTree = getChildTree(2,threeNodeList) ;
        // System.out.println(getChildTree);
        // 測試3
        List<Integer> treeIdList = getTreeInfo(getTree) ;
        System.out.println(treeIdList);
        // 測試4
        System.out.println(hasChildNode(2,threeNodeList)) ;
    }
}

四、原始碼地址

GitHub·地址
https://github.com/cicadasmile
GitEE·地址
https://gitee.com/cicadasmile

相關推薦

基於演算法樹形結構資料業務場景封裝解決方法

本文原始碼:GitHub·點這裡 || GitEE·點這裡 一、遞迴演算法 1、概念簡介 遞迴演算法的核心思想是通過將問題重複分解為同類的或其子問題的方式,從而可以使用統一的解決方式。很多程式語言支援方法或函式自我呼叫,簡單的說,就是在函式或方法體內,自身可以再次呼叫自身的方法結構。 2、基礎案例 這裡通過遞

資料庫多層資料運用演算法生成樹形資料

第一步:準備表結構及對應的表資料1.表結構create table City(id char(32) not null,name varchar2(30),parent_id char(32) //父級欄位)2.插入資料insert into City (id, name,

php當資料量不是很大的時候使用【迴圈出樹形結構】的一個使用者下面的所有人

前提是資料量不大的時候 1.一張表如下: 2.我們要通過遞迴實現樹形結構的一個人下面的所有人都顯示出來: <span style="font-size:18px;"><strong> public function test(){</

Java拼接json樹形結構

最近在專案開發過程中遇到一個問題,前臺需要用到echarts元件中的旭日圖來顯示層級關係,這就需要我將後臺Sql查詢出來的json陣列拼接成多級巢狀的樹形結構返回前臺 ,類似於 而我從資料庫中查出來的資料時這樣的: {"prog_level_id_1":"5","

Java獲取zTree標準結構資料優化

資料結構: var nodes = [ {name: "父節點1", children: [ {name: "子節點1"}, {name: "子節點2"} ]} ]; // 獲取標準JSON資料 public st

oracle11.2g查詢(樹形結構查詢)

轉自: 一 二 簡單語法介紹 一、樹型表結構: 節點ID 上級ID 節點名稱 二、公式: select 節點ID,節點名稱,level from 表 connect by prior 節點ID=上級節點ID start with 上級節點ID=

c++使用樸素演算法(自頂向)和動態規劃dp(帶備忘的自頂向自底向上)解決鋼條切割及執行例項結果

本博文資料來源於演算法導論第三版 動態規劃有兩種等價實現方法:帶備忘的自頂向下發(topDownWithMemoization),自底向上方法,付出額外的記憶體空間來節省計算時間,是典型的時空權衡,遞迴時會儲存每個子問題的解 長度n與對應價格p關係 1~10的對應最

java 遍歷樹形結構

//選單樹形結構 public JSONArray treeMenuList(JSONArray menuList, int parentId) { JSONArray childMenu = new JSONArray(); f

JS拼裝樹形結構的表格

資料格式: [{"id":2, "pid":1, "children":[{...},{...}]},{"id":3, "pid":1, "children":[{...},{...}]},.......]注意: 下面的樣例資料沒有children屬性,children屬性是

tomcat釋出工程後WEB-INF/classes檔案不編譯的解決方法

今天部署專案到tomcat,釋出完後,啟動tomcat,報class not found; 臨時找了個解決方案,由於專案是copy過來的,於是就將原來專案的classes下面編譯好的class檔案也一併拷過來了;但是治標不治本; 後來在我修改程式碼的時候,重新發布到tomc

資料結構實驗-C語言-二叉樹的建立前、中、後序遍歷的遞迴演算法和非遞迴演算法,求葉子結點數目求二叉樹深度判斷二叉樹是否相似求二叉樹左右子樹互換二叉樹層序遍歷的演算法,判斷二叉樹是否是完全二叉樹

1.實驗目的 熟練掌握二叉樹的二叉連結串列儲存結構的C語言實現。掌握二叉樹的基本操作-前序、中序、後序遍歷二叉樹的三種方法。瞭解非遞迴遍歷過程中“棧”的作用和狀態,而且能靈活運用遍歷演算法實現二叉樹的其它操作。 2.實驗內容 (1)二叉樹的二叉連結串列的建立 (2)二叉樹的前、中、後

資料結構週週練】016 利用演算法及孩子兄弟表示法建立樹、遍歷樹並求樹的深度

一、前言 從今天起,就給大家分享一些樹的程式碼啦,不僅僅是二叉樹,我們要弄明白,普通的樹用資料結構怎麼儲存,它有哪些操作,它可以實現哪些功能? 可能大家要問了,二叉樹不是還沒有寫完嗎,線索二叉樹呢?二叉排序樹呢?平衡二叉樹呢?大家不要急,我們通過二叉樹來入門樹的演算法及程式碼實現,然後學

資料結構週週練】015 利用演算法建立鏈式儲存的二叉樹並轉換左右孩子結點

一、前言 哈哈,今天就是程式設計師節啦,祝大家1024程式設計師節快樂。 今天要給大家分享的演算法是交換二叉樹是的左右孩子結點,比較簡單,需要建立一個結點用來暫存左孩子結點,下面給大家送上程式碼。 二、題目 將下圖用二叉樹存入,並交換二叉樹是的左右孩子結點。其中圓角矩形內為結點資

資料結構週週練】014 利用棧和非演算法求鏈式儲存的二叉樹是否為完全二叉樹

一、前言 首先,明天是個很重要的節日,以後我也會過這個節日,在這裡,提前祝所有程式猿們,猿猴節快樂,哦不,是1024程式設計師節快樂。 今天要給大家分享的演算法是判斷二叉樹是否為完全二叉樹,相信大家對完全二叉樹的概念並不陌生,如果是順序儲存就會很方便,那鏈式儲存怎麼判斷呢,我的做法是:若

資料結構週週練】013 利用棧和非演算法求二叉樹的高

一、前言 二叉樹的高是樹比較重要的一個概念,指的是樹中結點的最大層數本次演算法通過非遞迴演算法來求得樹的高度,借用棧來實現樹中結點的儲存。 學英語真的很重要,所以文中的註釋還有輸出以後會盡量用英語寫,文中出現的英語語法或者單詞使用錯誤,還希望各位英語大神能不吝賜教。 二、題目 將

資料結構週週練】012 利用佇列和非演算法實現二叉樹的層次遍歷

一、前言 二叉樹的遍歷是比較多樣化的遍歷,有很多種遍歷方式,先序遍歷,中序遍歷,後序遍歷,層次遍歷等等。本次給大家講的是層次遍歷,為了方便,我將題目中的資料改為編號,從左往右,從上往下依次遍歷。方便大家看到結果。 二、題目 將下圖用二叉樹存入,並通過層次遍歷方式,自上而下,從左往右對

二叉樹----資料結構:二叉樹的三種遍歷,利用演算法

二叉樹----資料結構:二叉樹的三種遍歷,利用遞迴演算法。     魯迅:總之歲月漫長,然而值得等待。   #define CHAR /* 字元型 */  /* #define INT /* 整型(二者選一) */  #

js遍歷樹形json結構 根據最後一個節點找到整個家族根據父節點找到所有的子節點根據層級關係寫成樹形結構

dataTree: [ { id: 1, address: "安徽", pid: 0 }, { id: 6, address: "安徽a", pid: 1 }, { id: 12, address: "安徽aa", pid: 6 },

鄰接矩陣儲存結構DFS非演算法

#include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 typedef struct { int data[MAXSIZE]; int top; }Seqstack; void init_seqst

js遍歷樹形json結構 根據最後一個節點找到整個家族根據父節點找到所有的子節點根據層級關係寫成樹形結構

dataTree: [ { id: 1, address: "安徽", pid: 0 }, { id: 6, address: "安徽a", pid: 1 }, { id: 12, address: "安徽aa", pid: 6