1. 程式人生 > >JAVA程式碼實現多級樹結構封裝物件(2018-09-26補充)

JAVA程式碼實現多級樹結構封裝物件(2018-09-26補充)

我們經常在程式碼裡會造一個樹結構物件,以方便前端使用。

以地區(區、鎮、村)為例
後臺一般對於樹結構物件在資料庫的結構是這樣的:

主鍵ID 名字 父ID
ID REGION_NAME PARENT_ID
121100 尼龍區 0
121100001 尼龍區鋼絲鎮 121100
121100001001 尼龍區鋼絲鎮螺絲村 121100001
  其實這樣返回給前端,前端是可以做成樹的,但是我這裡不是要說這種的,我遇到的是下邊的情況。
主鍵ID 名字 詞典表型別
ID REGION_NAME DICT_TYPE
121100 尼龍區 XZQH
121100001 尼龍區鋼絲鎮 XZQH
121100001001 尼龍區鋼絲鎮螺絲村 XZQH
231111 一般性支付 ZFFS

  資料庫的結構如上,並沒有樹結構,需要根據DICT_TYPE為XZQH的記錄取出來,然後封裝成樹結構返回給前端,前端要的樹結構類似如下:

這裡寫圖片描述

我的實現的邏輯是這樣的:

  • 首先根據DICT_TYPE取出相關的地區記錄。
  • 然後將區、鎮、村分別存到三個不同的map裡。
  • 最後,巢狀遍歷三個map的key,區裡邊套鎮、鎮裡邊套村,封裝物件。(最重要的地方)。

具體步驟:

1、建立一個物件,用來規範樹結構。

public class FpzjXzdwArray implements Serializable 	{
    private String value; //對應資料庫的ID
    private String text; //對應資料庫的region_name
    private List<FpzjXzdwArray> children;
    //省略get/set方法了
}

2、第一步我就省略了。

3、第二步像我這種情況就是根據ID了,長度為6的放到區map裡,長度為9的放到鎮map裡,長度為12的放到村map裡。

Map<String,FpzjXzdwArray> quMap = new HashMap<String,FpzjXzdwArray>();
Map<String,FpzjXzdwArray> zhenMap = new HashMap<String,FpzjXzdwArray>();
Map<String,FpzjXzdwArray> cunMap = new HashMap<String,FpzjXzdwArray>();

4、巢狀遍歷三個map,首先縷縷我們的步驟。

  以一個小例子為例,我們現在有一個大箱子、2箇中箱子(1紅、1藍)、6個紅藍小箱子(3紅、3藍)。要求是把大箱子裡裝上中箱子,中箱子裡要顏色對應裝進去小箱子。
 **正確邏輯:**如果讓一個正常人來做,我們的邏輯都是一樣的,要先把顏色對應的小箱子放到中箱子裡以後,才會把中箱子放到大箱子裡,對嗎?
 **錯誤邏輯:**如果你非要先把中箱子放到大箱子以後,再去拿對應顏色的小箱子放進中箱子裡去的話,這樣帶來的一個問題就是,你必須要先把大箱子開啟才可以完成這種事。所以這種邏輯就是錯誤的。

  這個例子反映到程式碼裡也是一樣,如果你先往區物件裡塞進鎮物件集合,然後再去往鎮物件裡塞對應的村物件,就會像上邊的第二個步驟一樣,邏輯就錯了。我的程式碼如下:(最下邊還有別人分享給我的好方法,先貼上我的,瞬間感覺自己弱爆了

for(String qu:quMap.keySet()){ //遍歷所有的區
			for(String zhen:zhenMap.keySet()){ //遍歷所有的鎮
				if(qu.equals(zhen.substring(0,6))){ //該區下找到該鎮
					FpzjXzdwArray zhenXzdw = null;//定義這個是有必要的,這樣可以先完成對村物件塞到鎮物件裡,然後再完成鎮物件塞到區物件的步驟。
					for(String cun:cunMap.keySet()){ //有區有鎮,然後再找下一級村
						if(zhen.equals(cun.substring(0,9))){ //該鎮下找到村
							zhenXzdw = zhenMap.get(zhen); //得到該鎮物件,
							List<FpzjXzdwArray> xzdwArrayZhenList = zhenXzdw.getChildren(); //取出鎮物件下的村集合
							if(xzdwArrayZhenList == null){
								xzdwArrayZhenList = new ArrayList<>();
								xzdwArrayZhenList.add(cunMap.get(cun));
								zhenXzdw.setChildren(xzdwArrayZhenList); //將符合該鎮下的村塞到鎮物件裡
							}else{
								xzdwArrayZhenList.add(cunMap.get(cun));
								zhenXzdw.setChildren(xzdwArrayZhenList); //將符合該鎮下的村塞到鎮物件裡
							}
						}
					}
					FpzjXzdwArray quXzdw = quMap.get(qu); //得到該區物件,
					List<FpzjXzdwArray> xzdwArrayList = quXzdw.getChildren();//取出區物件下的鎮集合
					if(xzdwArrayList == null){
						xzdwArrayList = new ArrayList<>();
						xzdwArrayList.add(zhenXzdw);
						quXzdw.setChildren(xzdwArrayList); //將符合該區下的鎮物件塞到區物件裡
						quMap.put(qu,quXzdw);
					}else{
						xzdwArrayList.add(zhenXzdw);
						quXzdw.setChildren(xzdwArrayList);//將符合該區下的鎮物件塞到區物件裡
						quMap.put(qu,quXzdw);
					}
				}
			}
		}
		return quMap.values();

以上就是我寫的實現的邏輯,我還沒有用上遞迴,本質是這樣。
消耗的時間我也測試了,對我來說幾毫秒,最多7ms
我的資料的數量是:

數量
總數 8 66 674

遍歷的總次數:866674=? //其實也挺多的次數。。

分享一:

  在我加的技術群裡吆喝了半天,有一位朋友分享他們的工具類,我感覺寫的很好了。他需要資料的結構是:

主鍵ID 名字 父ID
ID REGION_NAME PARENT_ID
121100 尼龍區 0
121100001 尼龍區鋼絲鎮 121100
121100001001 尼龍區鋼絲鎮螺絲村 121100001
對應封裝好的實體類物件可以是這樣的:
public class TestTree{
    private String id;
    private String name;
    private String pid;
    private List<TestTree> testTrees;
    //省略get/set方法
 }

賦上他給我的兩個工具類:
工具類下載地址
使用的主要邏輯在TreeUtils類裡,在這裡邊我加了一個main方法,模擬了一個例子,大家可以參考。最後實現的結果如下圖:

這裡寫圖片描述

他的這個工具類的好處是,利用了反射,只要你的資料結構符合上邊的id、pid、name這樣的資料,叫什麼名字都無所謂,不管多少層,都可以給弄出來。覺得這個特別好了。感謝@小太陽の !!
   經過使用,發現,該方法,在很多的時候,特別慢。最後又找到一個好方法。

分享二:(2018-09-26補充)

   發現了一個寫法超級牛掰的多級樹,我修改了一下,程式碼如下:

package znxd.tjzb.util;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import znxd.tjzb.model.region.RegionBeanTree;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2018/9/26.
 */
public class TreeToolUtils {

    private List<RegionBeanTree> rootList; //根節點物件存放到這裡

    private List<RegionBeanTree> bodyList; //其他節點存放到這裡,可以包含根節點

    public TreeToolUtils(List<RegionBeanTree> rootList, List<RegionBeanTree> bodyList) {
        this.rootList = rootList;
        this.bodyList = bodyList;
    }

    public List<RegionBeanTree> getTree(){   //呼叫的方法入口
        if(bodyList != null && !bodyList.isEmpty()){
        //宣告一個map,用來過濾已操作過的資料
            Map<String,String> map = Maps.newHashMapWithExpectedSize(bodyList.size());
            rootList.forEach(beanTree -> getChild(beanTree,map));
            return rootList;
        }
        return null;
    }

    public void getChild(RegionBeanTree beanTree,Map<String,String> map){
        List<RegionBeanTree> childList = Lists.newArrayList();
        bodyList.stream()
                .filter(c -> !map.containsKey(c.getCode()))
                .filter(c ->c.getPid().equals(beanTree.getCode()))
                .forEach(c ->{
                    map.put(c.getCode(),c.getPid());
                    getChild(c,map);
                    childList.add(c);
                });
        beanTree.setChildren(childList);
    }

    public static void main(String[] args){
        RegionBeanTree beanTree1 = new RegionBeanTree();
        beanTree1.setCode("540000");
        beanTree1.setLabel("西藏省");
        beanTree1.setPid("100000"); //最高節點
        RegionBeanTree beanTree2 = new RegionBeanTree();
        beanTree2.setCode("540100");
        beanTree2.setLabel("拉薩市");
        beanTree2.setPid("540000");
        RegionBeanTree beanTree3 = new RegionBeanTree();
        beanTree3.setCode("540300");
        beanTree3.setLabel("昌都市");
        beanTree3.setPid("540000");
        RegionBeanTree beanTree4 = new RegionBeanTree();
        beanTree4.setCode("540121");
        beanTree4.setLabel("林周縣");
        beanTree4.setPid("540100");
        RegionBeanTree beanTree5 = new RegionBeanTree();
        beanTree5.setCode("540121206");
        beanTree5.setLabel("阿朗鄉");
        beanTree5.setPid("540121");
        RegionBeanTree beanTree6 = new RegionBeanTree();
        List<RegionBeanTree> rootList = new ArrayList<>();
        rootList.add(beanTree1);
        List<RegionBeanTree> bodyList = new ArrayList<>();
        bodyList.add(beanTree1);
        bodyList.add(beanTree2);
        bodyList.add(beanTree3);
        bodyList.add(beanTree4);
        bodyList.add(beanTree5);
        TreeToolUtils utils =  new TreeToolUtils(rootList,bodyList);
        List<RegionBeanTree> result =  utils.getTree();
        result.get(0);
    }
}

   說實話,這種寫法我反正寫不出來,只能看懂,汗~,例子我放到最後了,大家可以下載下來直接執行即可。速度槓槓的。

造樹我覺得是挺重要的,挺常用的,如果有多級樹,我這種方式就不適用,所以我想找到一個可以封裝多級樹的好程式碼,希望有能看到,留言共享一下,我再把好的方法補充到這個文章裡

相關推薦

JAVA程式碼實現多級結構封裝物件2018-09-26補充

我們經常在程式碼裡會造一個樹結構物件,以方便前端使用。 以地區(區、鎮、村)為例 後臺一般對於樹結構物件在資料庫的結構是這樣的: 主鍵ID 名字 父ID ID REGION_NAME PARENT_ID 121100 尼龍區 0 1211

JAVA代碼實現多級結構封裝對象

char parent set方法 get innodb 代碼 not static drop 樹結構在開發中經常遇到。例如:部門、菜單、員工架構等等。下面用部門作為例子構造部門結構樹 1、部門表:dept -- ----------------------------

java程式碼實現的高度和節點數

求二叉樹的高度 public int getHeight(TreeNode node){ if(node == null){ return 0; } int i = getHeight(nod

智慧自動播放工具2018/11/13更新

描述:實現智慧樹教學視訊的自動播放,跳過彈題,自動下一節 基於前輩的更新版本 2018-10-07更新:修復自動播放按鈕點選消失的問題 var fa=$("body"); var btn=$("<li></li>");

【資料結構】二叉順序儲存、鏈式儲存JAVA程式碼實現

二叉樹是一種非線性的資料結構。它是由n個有限元素的集合,該集合或者為空、或者由一個稱為根(root)的元素及兩顆不相交的、被分別稱為左子樹、右子樹的二叉樹組成。當集合為空時,稱該二叉樹為空二叉樹。在二叉樹中,一個元素也可以稱做一個結點。二叉樹是有序的,即若將其左右兩個子樹顛倒

演算法學習——中國大學MOOC-陳越、何欽銘-資料結構-起步能力自測題——java程式碼實現

自測-1 列印沙漏 (20 point(s)) 本題要求你寫個程式把給定的符號列印成沙漏的形狀。例如給定17個“*”,要求按下列格式列印 ***** *** * *** ***** 所謂“沙漏形狀”,是指每行輸出奇數個符號;各行符號中心對齊;相鄰兩行符號數差2;符號數先從大

java程式碼實現根據JSON檔案進行批量檔案重新命名或者改目錄結構

使用JAVA程式碼根據JSON檔案進行批量修改檔名以及路徑 某些網站視訊加密分割,首先去下載格式轉換工具,再用chrome F12開啟控制檯,找到json檔案進行檔案還原 json資料: {“message”:“hello”,“result”:[],“status”:200

資料結構4--佇列java程式碼實現佇列的鏈式儲存

1.什麼是佇列?      佇列也叫隊,時允許在一段進行擦汗如另一端進行刪除的運算受限的線性表。區別佇列和棧:棧時先進後出,佇列時先進先出。                 &nbs

資料結構2--線性表java程式碼實現線性表的鏈式儲存

1.鏈式儲存       2.分析       每個節點為一個物件,該物件包含資料域和指標域        整條單鏈表為一個物件,他和節點物件進行組合。  3.

資料結構1--線性表java程式碼實現線性表的順序儲存

1.資料結構的概念      資料:資訊載體,計算機處理的物件的總稱      資料元素:也稱結點,組成資料的基本單位      資料項:資料項是資料的最小單位     &n

買什麼資料結構與演算法,這裡有:動態圖解十大經典排序演算法JAVA程式碼實現

上篇的動圖資料結構反響不錯,這次來個動圖排序演算法大全。資料結構與演算法,齊了。 幾張動態圖捋清Java常用資料結構及其設計原理 本文將採取動態圖+文字描述+正確的java程式碼實現來講解以下十大排序演算法: 氣泡排序 選擇排序 插入排序 希爾排序

【資料結構與演算法】回溯法解決N皇后問題,java程式碼實現

N皇后問題 問題描述 在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法,這稱為八皇后問題。 延伸一下,便為N皇后問題。 核心思想 解決N皇后問題有兩個關鍵點。一是如何進行放置棋子,二是如何驗證棋子是否符合

【資料結構與演算法】貪心演算法解決揹包問題。java程式碼實現

揹包問題(貪心演算法) 貪心演算法思想 簡單的說,就是將大問題轉化為最優子問題,例如本題所要求的,揹包容量有限,要想使物品的總價值最高,那麼,我們必須儘可能的選擇權重高的(即單位價值更高)的物品進行裝載。 在揹包問題中,物品是可拆的,即可以分成任意部分進行裝載,而最終實現的目標是

關於資料結構演算法中的比較排序(一)Java程式碼實現

     現在已經是10月份,秋招正在進行,不知道是不是有的人會和我一樣正在瘋狂的複習起資料結構,在這裡我將就常見的幾種比較排序做一些簡單的解析,同時附上具體的程式碼實現。 1.氣泡排序 氣泡排序通常是我們最先接觸道的比較排序的一種,具體排序步驟如下: 1.比較相鄰的元

【資料結構與演算法】之單鏈表、雙鏈表、迴圈連結串列的基本介紹及其Java程式碼實現---第三篇

一、連結串列的基本介紹 連結串列的定義:連結串列是一種遞迴的資料結構,它或者為空(null),或者是指向一個結點(node)的引用,該結點含有一個泛型的元素和一個指向另一條連結串列的引用。----Algorithms  Fourth  Edition   常見的連結串

的層次遍歷Java程式碼實現

  與樹的前中後序遍歷的DFS思想不同,層次遍歷用到的是BFS思想。一般DFS用遞迴去實現(也可以用棧實現),BFS需要用佇列去實現。 層次遍歷的步驟是: 1.對於不為空的結點,先把該結點加入到佇列中 2.從隊中拿出結點,如果該結點的左右結點不為空,就分別把左右結點加入到佇列

Java實現簡單結構

Node實體: package treeTest; import java.io.Serializable; import java.util.List; /** * ClassName: No

劍指Offer 面試題34:二叉中和為某一值的路徑 Java程式碼實現

題目:輸入一棵二叉樹和整數,打印出二叉樹中節點值得和為輸入整數的所有路徑。從樹的根節點開始往下一直到葉節點所經過的節點形成一條路徑。 解題思路:路徑從根節點開始,應該用類似於前序遍歷的方式訪問樹節點。

紅黑Red-Black tree初步詳解Java程式碼實現

紅黑樹Red-Blacktree初步詳解 本部落格的參考資料: 演算法導論 http://blog.csdn.net/v_july_v/article/details/6105630 http://www.cnblogs.com/skywang12345/p/3624343

【資料結構】圖最短路徑Dijkstra演算法JAVA程式碼實現

最短路徑的概念最短路徑的問題是比較典型的應用問題。在圖中,確定了起始點和終點之後,一般情況下都可以有很多條路徑來連線兩者。而邊或弧的權值最小的那一條路徑就稱為兩點之間的最短路徑,路徑上的第一個頂點為源點,最後一個頂點為終點。圖的最短路徑的演算法有很多,本文主要介紹狄克斯特拉(