Java中id,pid格式數(shù)據(jù)轉(zhuǎn)樹(shù)和森林結(jié)構(gòu)工具類實(shí)現(xiàn)
樹(shù)形結(jié)構(gòu)很多地方都有應(yīng)用,比如我們?cè)跇?gòu)造網(wǎng)站后臺(tái)的授權(quán)限樹(shù)的時(shí)候,再比如我們?cè)谠O(shè)計(jì)多級(jí)留言的時(shí)候、還有分類等等。
有些時(shí)候我們的樹(shù)形結(jié)構(gòu)并不需要過(guò)多設(shè)計(jì),這是因?yàn)槲覀兊暮芏鄷r(shí)候?qū)@棵樹(shù)的要求不高(兩層、三層就行了),這時(shí)候我們很容易的會(huì)按照層級(jí)劃分樹(shù)形結(jié)構(gòu),然后查詢數(shù)據(jù)庫(kù)的時(shí)候會(huì)一層一層的嵌套查詢。如果層次比較淺這種做法是可取的(或者我們本來(lái)就不打算一次將樹(shù)加載完全,而是在需要時(shí)再加載,那分層級(jí)的多次加載也許有用武之地)。但是考慮這種情況:我們的樹(shù)比較深,而且要一次加載完全。要是按照一層一層的加載原則,那么光是訪問(wèn)數(shù)據(jù)庫(kù)的查詢語(yǔ)句就是指數(shù)形式的了。性能肯定不好。那么除了一層一層的查詢好有更好的辦法嗎?肯定是有的,多查詢一些資料會(huì)發(fā)現(xiàn)這種做法比較常見(jiàn)了:(id,pid),通俗說(shuō)就是一個(gè)節(jié)點(diǎn)只需要記住自己的id和父親的id(根節(jié)點(diǎn)沒(méi)有pid可以設(shè)置一個(gè)特殊值)就可以擁有呈現(xiàn)這棵樹(shù)的完整結(jié)構(gòu)全部信息了,仔細(xì)想一想自己學(xué)過(guò)的數(shù)據(jù)結(jié)構(gòu),是不是這樣的?好了這樣一來(lái)我們?cè)谠O(shè)計(jì)數(shù)據(jù)庫(kù)的時(shí)候就可以很輕松的設(shè)計(jì)一棵樹(shù)的樹(shù)形結(jié)構(gòu)了。那么有個(gè)問(wèn)題,我們?cè)谡宫F(xiàn)出來(lái)的時(shí)候總不能直接顯示一連串的(id,pid)集合吧。我們要的是樹(shù)形結(jié)構(gòu)。這時(shí)候我們其實(shí)非常想實(shí)現(xiàn)的是從(id,pid)到
(id,children【】)的轉(zhuǎn)化。畢竟我們?cè)谡宫F(xiàn)樹(shù)形結(jié)構(gòu)的時(shí)候后一種格式更適合頁(yè)面的呈現(xiàn),而前一種比較適合數(shù)據(jù)的存儲(chǔ)格式。
好了廢話不多說(shuō)了,下面是代碼示例:
首先是自定義節(jié)點(diǎn)類:
/** * 節(jié)點(diǎn)類 * @author bearsmall * */ public class TreeNode { private int id;//主鍵ID private int pid;//父節(jié)點(diǎn)ID private Object content;//節(jié)點(diǎn)內(nèi)容 private List<TreeNode> children = new ArrayList<TreeNode>();//子孫節(jié)點(diǎn) public TreeNode(int id, Object content) { this.id = id; this.content = content; } public TreeNode(int id, int pid, Object content) { this.id = id; this.pid = pid; this.content = content; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } public Object getContent() { return content; } public void setContent(Object content) { this.content = content; } public List<TreeNode> getChildren() { return children; } public void setChildren(List<TreeNode> children) { this.children = children; } @Override public String toString() { return "TreeNode [id=" + id + ", pid=" + pid + ", content=" + content + ", children=" + children + "]"; } }
然后是樹(shù)節(jié)點(diǎn)管理類:
/** * 樹(shù)節(jié)點(diǎn)管理類 * * @author bearsmall * */ public class TreeNodeManager { private List<TreeNode> list;// 樹(shù)的所有節(jié)點(diǎn) public TreeNodeManager(TreeNode[] items) { list = new ArrayList<TreeNode>(); for (TreeNode treeNode : items) { list.add(treeNode); } } public TreeNodeManager(List<TreeNode> items) { list = items; } /** * 根據(jù)節(jié)點(diǎn)ID獲取一個(gè)節(jié)點(diǎn) * * @param id * 節(jié)點(diǎn)ID * @return 對(duì)應(yīng)的節(jié)點(diǎn)對(duì)象 */ public TreeNode getTreeNodeAT(int id) { for (TreeNode treeNode : list) { if (treeNode.getId() == id) return treeNode; } return null; } /** * 獲取樹(shù)的根節(jié)點(diǎn) * * @return 一棵樹(shù)的根節(jié)點(diǎn) */ public TreeNode getRoot() { for (TreeNode treeNode : list) { if (treeNode.getPid() == 0) return treeNode; } return null; } }
最后是樹(shù)節(jié)點(diǎn)轉(zhuǎn)化類:
/** * 節(jié)點(diǎn)歸并類 * @author bearsmall * */ public class TreeNodeMerger { /** * 將節(jié)點(diǎn)數(shù)組歸并為一棵樹(shù)(填充節(jié)點(diǎn)的children域) * 時(shí)間復(fù)雜度為O(n^2) * @param items 節(jié)點(diǎn)域 * @return */ public static TreeNode merge(TreeNode[] items){ TreeNodeManager treeNodeManager = new TreeNodeManager(items); for (TreeNode treeNode : items) { if(treeNode.getPid()!=0){ TreeNode t = treeNodeManager.getTreeNodeAT(treeNode.getPid()); t.getChildren().add(treeNode); } } return treeNodeManager.getRoot(); } /** * 將節(jié)點(diǎn)數(shù)組歸并為一棵樹(shù)(填充節(jié)點(diǎn)的children域) * 時(shí)間復(fù)雜度為O(n^2) * @param items 節(jié)點(diǎn)域 * @return */ public static TreeNode merge(List<TreeNode> items){ TreeNodeManager treeNodeManager = new TreeNodeManager(items); for (TreeNode treeNode : items) { if(treeNode.getPid()!=0){ TreeNode t = treeNodeManager.getTreeNodeAT(treeNode.getPid()); t.getChildren().add(treeNode); } } return treeNodeManager.getRoot(); } }
簡(jiǎn)單測(cè)試一下:
public class Main { public static void main(String[] args) { TreeNode[] treeNodes = new TreeNode[10]; treeNodes[0] = new TreeNode(1, 0, ""); treeNodes[1] = new TreeNode(2, 1, ""); treeNodes[2] = new TreeNode(3, 1, ""); treeNodes[3] = new TreeNode(4, 2, ""); treeNodes[4] = new TreeNode(5, 3, ""); treeNodes[5] = new TreeNode(6, 4, ""); treeNodes[6] = new TreeNode(7, 3, ""); treeNodes[7] = new TreeNode(8, 5, ""); treeNodes[8] = new TreeNode(9, 6, ""); treeNodes[9] = new TreeNode(10, 9, ""); TreeNode treeNode = TreeNodeMerger.merge(treeNodes); JSONArray jsonArray = JSONArray.fromObject(treeNode); System.out.println(jsonArray); } }
輸出結(jié)果:
[{ "children" : [{ "children" : [{ "children" : [{ "children" : [{ "children" : [{ "children" : [], "pid" : 9, "id" : 10, "content" : "" } ], "pid" : 6, "id" : 9, "content" : "" } ], "pid" : 4, "id" : 6, "content" : "" } ], "pid" : 2, "id" : 4, "content" : "" } ], "pid" : 1, "id" : 2, "content" : "" }, { "children" : [{ "children" : [{ "children" : [], "pid" : 5, "id" : 8, "content" : "" } ], "pid" : 3, "id" : 5, "content" : "" }, { "children" : [], "pid" : 3, "id" : 7, "content" : "" } ], "pid" : 1, "id" : 3, "content" : "" } ], "pid" : 0, "id" : 1, "content" : "" } ]
這種格式是不是更清晰呢?
森林管理類:
/** * 森林節(jié)點(diǎn)管理類 * * @author bearsmall * */ public class ForestNodeManager { private List<TreeNode> list;// 森林的所有節(jié)點(diǎn) public ForestNodeManager(TreeNode[] items) { list = new ArrayList<TreeNode>(); for (TreeNode treeNode : items) { list.add(treeNode); } } public ForestNodeManager(List<TreeNode> items) { list = items; } /** * 根據(jù)節(jié)點(diǎn)ID獲取一個(gè)節(jié)點(diǎn) * * @param id * 節(jié)點(diǎn)ID * @return 對(duì)應(yīng)的節(jié)點(diǎn)對(duì)象 */ public TreeNode getTreeNodeAT(int id) { for (TreeNode treeNode : list) { if (treeNode.getId() == id) return treeNode; } return null; } /** * 獲取樹(shù)的根節(jié)點(diǎn)【一個(gè)森林對(duì)應(yīng)多顆樹(shù)】 * * @return 樹(shù)的根節(jié)點(diǎn)集合 */ public List<TreeNode> getRoot() { List<TreeNode> roots = new ArrayList<TreeNode>(); for (TreeNode treeNode : list) { if (treeNode.getPid() == 0) roots.add(treeNode); } return roots; } }
森林節(jié)點(diǎn)歸并類:
/** * 節(jié)點(diǎn)歸并類 * @author bearsmall * */ public class ForestNodeMerger { /** * 將節(jié)點(diǎn)數(shù)組歸并為一個(gè)森林(多棵樹(shù))(填充節(jié)點(diǎn)的children域) * 時(shí)間復(fù)雜度為O(n^2) * @param items 節(jié)點(diǎn)域 * @return 多棵樹(shù)的根節(jié)點(diǎn)集合 */ public static List<TreeNode> merge(TreeNode[] items){ ForestNodeManager forestNodeManager = new ForestNodeManager(items); for (TreeNode treeNode : items) { if(treeNode.getPid()!=0){ TreeNode t = forestNodeManager.getTreeNodeAT(treeNode.getPid()); t.getChildren().add(treeNode); } } return forestNodeManager.getRoot(); } /** * 將節(jié)點(diǎn)數(shù)組歸并為一個(gè)森林(多棵樹(shù))(填充節(jié)點(diǎn)的children域) * 時(shí)間復(fù)雜度為O(n^2) * @param items 節(jié)點(diǎn)域 * @return 多棵樹(shù)的根節(jié)點(diǎn)集合 */ public static List<TreeNode> merge(List<TreeNode> items){ ForestNodeManager forestNodeManager = new ForestNodeManager(items); for (TreeNode treeNode : items) { if(treeNode.getPid()!=0){ TreeNode t = forestNodeManager.getTreeNodeAT(treeNode.getPid()); t.getChildren().add(treeNode); } } return forestNodeManager.getRoot(); } }
測(cè)一下:
public class Main2 { public static void main(String[] args) { TreeNode[] treeNodes = new TreeNode[10]; treeNodes[0] = new TreeNode(1, 0, ""); treeNodes[1] = new TreeNode(2, 0, ""); treeNodes[2] = new TreeNode(3, 1, ""); treeNodes[3] = new TreeNode(4, 2, ""); treeNodes[4] = new TreeNode(5, 3, ""); treeNodes[5] = new TreeNode(6, 4, ""); treeNodes[6] = new TreeNode(7, 3, ""); treeNodes[7] = new TreeNode(8, 5, ""); treeNodes[8] = new TreeNode(9, 6, ""); treeNodes[9] = new TreeNode(10, 9, ""); List<TreeNode> tns = ForestNodeMerger.merge(treeNodes); JSONArray jsonArray = JSONArray.fromObject(tns); System.out.println(jsonArray); } }
打印輸出:
[{ "children" : [{ "children" : [{ "children" : [{ "children" : [], "pid" : 5, "id" : 8, "content" : "" } ], "pid" : 3, "id" : 5, "content" : "" }, { "children" : [], "pid" : 3, "id" : 7, "content" : "" } ], "pid" : 1, "id" : 3, "content" : "" } ], "pid" : 0, "id" : 1, "content" : "" }, { "children" : [{ "children" : [{ "children" : [{ "children" : [{ "children" : [], "pid" : 9, "id" : 10, "content" : "" } ], "pid" : 6, "id" : 9, "content" : "" } ], "pid" : 4, "id" : 6, "content" : "" } ], "pid" : 2, "id" : 4, "content" : "" } ], "pid" : 0, "id" : 2, "content" : "" } ]
到此這篇關(guān)于Java中id,pid格式數(shù)據(jù)轉(zhuǎn)樹(shù)和森林結(jié)構(gòu)工具類實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java id,pid格式數(shù)據(jù)轉(zhuǎn)樹(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java詳解如何將excel數(shù)據(jù)轉(zhuǎn)為樹(shù)形
- JAVA如何轉(zhuǎn)換樹(shù)結(jié)構(gòu)數(shù)據(jù)代碼實(shí)例
- JAVA后臺(tái)轉(zhuǎn)換成樹(shù)結(jié)構(gòu)數(shù)據(jù)返回給前端的實(shí)現(xiàn)方法
- java后端把數(shù)據(jù)轉(zhuǎn)換為樹(shù),map遞歸生成json樹(shù),返回給前端(后臺(tái)轉(zhuǎn)換)
- JSON復(fù)雜數(shù)據(jù)處理之Json樹(shù)形結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)Java對(duì)象并存儲(chǔ)到數(shù)據(jù)庫(kù)的實(shí)現(xiàn)
相關(guān)文章
[Spring MVC]-詳解SpringMVC的各種參數(shù)綁定方式
本篇文章主要介紹了SpringMVC的各種參數(shù)綁定方式 ,具有一定的參考價(jià)值,有需要的可以了解一下。2016-12-12Java OCR tesseract 圖像智能文字字符識(shí)別技術(shù)實(shí)例代碼
這篇文章主要介紹了Java OCR tesseract 圖像智能文字字符識(shí)別技術(shù)實(shí)例代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-06-06在SpringBoot中使用MongoDB的簡(jiǎn)單場(chǎng)景案例
MongoDB 是一種非關(guān)系型數(shù)據(jù)庫(kù),也被稱為 NoSQL 數(shù)據(jù)庫(kù),它主要以文檔的形式存儲(chǔ)數(shù)據(jù),本文給大家介紹了在SpringBoot中使用MongoDB的簡(jiǎn)單場(chǎng)景案例,并通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-09-09WIN7系統(tǒng)JavaEE(java)環(huán)境配置教程(一)
這篇文章主要介紹了WIN7系統(tǒng)JavaEE(java+tomcat7+Eclipse)環(huán)境配置教程,本文重點(diǎn)在于java配置,感興趣的小伙伴們可以參考一下2016-06-06Java超詳細(xì)教你寫(xiě)一個(gè)學(xué)籍管理系統(tǒng)案例
這篇文章主要介紹了怎么用Java來(lái)寫(xiě)一個(gè)學(xué)籍管理系統(tǒng),學(xué)籍管理主要涉及到學(xué)生信息的增刪查改,本篇將詳細(xì)的實(shí)現(xiàn),感興趣的朋友跟隨文章往下看看吧2022-03-03springboot實(shí)現(xiàn)圖片上傳與下載功能
這篇文章主要為大家詳細(xì)介紹了后端spring項(xiàng)目經(jīng)常要做的功能,實(shí)現(xiàn)圖片上傳和下載,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-12-12