Java中id,pid格式數(shù)據(jù)轉(zhuǎn)樹(shù)和森林結(jié)構(gòu)工具類(lèi)實(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í)候、還有分類(lèi)等等。
有些時(shí)候我們的樹(shù)形結(jié)構(gòu)并不需要過(guò)多設(shè)計(jì),這是因?yàn)槲覀兊暮芏鄷r(shí)候?qū)@棵樹(shù)的要求不高(兩層、三層就行了),這時(shí)候我們很容易的會(huì)按照層級(jí)劃分樹(shù)形結(jié)構(gòu),然后查詢(xún)數(shù)據(jù)庫(kù)的時(shí)候會(huì)一層一層的嵌套查詢(xún)。如果層次比較淺這種做法是可取的(或者我們本來(lái)就不打算一次將樹(shù)加載完全,而是在需要時(shí)再加載,那分層級(jí)的多次加載也許有用武之地)。但是考慮這種情況:我們的樹(shù)比較深,而且要一次加載完全。要是按照一層一層的加載原則,那么光是訪問(wèn)數(shù)據(jù)庫(kù)的查詢(xún)語(yǔ)句就是指數(shù)形式的了。性能肯定不好。那么除了一層一層的查詢(xún)好有更好的辦法嗎?肯定是有的,多查詢(xún)一些資料會(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ǔ)格式。
好了廢話(huà)不多說(shuō)了,下面是代碼示例:
首先是自定義節(jié)點(diǎn)類(lèi):
/**
* 節(jié)點(diǎn)類(lèi)
* @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)管理類(lèi):
/**
* 樹(shù)節(jié)點(diǎn)管理類(lèi)
*
* @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)化類(lèi):
/**
* 節(jié)點(diǎn)歸并類(lèi)
* @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" : ""
}
]這種格式是不是更清晰呢?
森林管理類(lèi):
/**
* 森林節(jié)點(diǎn)管理類(lèi)
*
* @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)歸并類(lèi):
/**
* 節(jié)點(diǎn)歸并類(lèi)
* @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)工具類(lèi)實(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)文章
java算法題解LeetCode30包含min函數(shù)的棧實(shí)例
這篇文章主要為大家介紹了java算法題解LeetCode30包含min函數(shù)的棧實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Springboot項(xiàng)目消費(fèi)Kafka數(shù)據(jù)的方法
本文詳細(xì)介紹了如何在Spring Boot項(xiàng)目中配置和實(shí)現(xiàn)Kafka消費(fèi)者和生產(chǎn)者,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-01-01
淺談SpringMVC之視圖解析器(ViewResolver)
本篇文章主要介紹了淺談SpringMVC之視圖解析器(ViewResolver),具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
Java的Struts框架中Action的編寫(xiě)與攔截器的使用方法
這篇文章主要介紹了Java的Struts框架中Action的編寫(xiě)與攔截器的使用方法,Struts框架是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下2015-11-11
Java基礎(chǔ)之詳解基本數(shù)據(jù)類(lèi)型的使用
今天給大家?guī)?lái)的是關(guān)于Java基礎(chǔ)的相關(guān)知識(shí),文章圍繞著基本數(shù)據(jù)類(lèi)型的使用展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
Windows本地安裝啟動(dòng)Nacos過(guò)程
本文介紹了如何下載、配置和啟動(dòng)Nacos,包括下載Nacos、配置單機(jī)模式、配置數(shù)據(jù)庫(kù)和啟動(dòng)Nacos等步驟2026-01-01
java異步編程的7種實(shí)現(xiàn)方式小結(jié)
異步處理的實(shí)現(xiàn)方式有很多種,常見(jiàn)多線(xiàn)程,消息中間件,發(fā)布訂閱的廣播模式,本文就詳細(xì)的介紹java異步編程的7種實(shí)現(xiàn)方式,感興趣的可以了解一下2023-03-03

