在個人項目中,經常會用到樹形結構的數據,最爲明顯的就是左邊菜單欄,相似於window folder同樣的東西。前端
而我以前一直是藉助前端封裝好的ZTree等工具實現展現,然後臺則一般使用遞歸進行數據的查找。一般,咱們在設計數據庫表的時候,通常會使用三個字段:id,name,pid。以下圖所示:java
首先是創建實體類:算法
<span style="font-family:KaiTi_GB2312;font-size:18px;"> private String id; private String name; private String pid;</span>
編寫實體類的get和set方法。sql
而後,咱們一般會有如下的幾個方法(一般狀況,封裝粒度不一樣,方法的實現個數和內容也不一樣):數據庫
<span style="font-family:KaiTi_GB2312;font-size:18px;">public List<TreeEntity> findAllParents() { String sql = "select * from test where pid is null or pid='' "; List<TreeEntity> treeList = null; try { conn = DbUtil.getConnection(); pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); treeList = new ArrayList<TreeEntity>(); while (rs.next()) { TreeEntity myTree = new TreeEntity(); myTree.setId(rs.getString("id")); myTree.setName(rs.getString("name")); myTree.setPid(rs.getString("pid")); treeList.add(myTree); } } catch (SQLException e) { e.printStackTrace(); } finally { DbUtil.close(pstmt); DbUtil.close(conn); } return treeList; }</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;">public List<TreeEntity> findChildByPid(String pid) { String sql = "select * from test where pid='" + pid + "'"; List<TreeEntity> treeList = null; try { conn = DbUtil.getConnection(); pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); treeList = new ArrayList<TreeEntity>(); while (rs.next()) { TreeEntity myTree = new TreeEntity(); myTree.setId(rs.getString("id")); myTree.setName(rs.getString("name")); myTree.setPid(rs.getString("pid")); treeList.add(myTree); } } catch (SQLException e) { e.printStackTrace(); } finally { DbUtil.close(pstmt); DbUtil.close(conn); } return treeList; }</span>
備註:這兩個方法能夠合併,這裏是爲了讓本身更好的理解,而寫了兩個方法。能夠判斷傳入的pid的值,肯定其查找的是父節點,仍是根據父節點查找子節點。數據結構
<span style="font-family:KaiTi_GB2312;font-size:18px;"> public boolean HasChild(String pid) { boolean flag = false; String sql = "select * from test where pid='" + pid + "'"; int count = 0; try { conn = DbUtil.getConnection(); pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); while(rs.next()){ count++; } if (count > 0) { flag = true; } } catch (SQLException e) { e.printStackTrace(); } finally { DbUtil.close(pstmt); DbUtil.close(conn); } return flag; }</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;"> public void BindChildByParent(String pid, String prefix) { if (this.HasChild(pid)) { // 獲得當前父節點下的全部孩子 List<TreeEntity> list = this.findChildByPid(pid); // 循環打印當前父節點下的孩子 for (int i = 0; i < list.size(); i++) { System.out.println("|----"+prefix+list.get(i).getName()); if (this.HasChild(list.get(i).getId())) { this.BindChildByParent(list.get(i).getId(),"--"); } } } }</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;"> public void TreeHtml() { // 找到全部的父節點 List<TreeEntity> treeList1 = this.findAllParents(); if (treeList1 != null) { for (int i = 0; i < treeList1.size(); i++) { TreeEntity tree = treeList1.get(i); // 打印父節點 System.out.println("|--" + tree.getName()); // 綁定孩子 this.BindChildByParent(tree.getId(), ""); } } else { System.out.println("沒有數據!"); } }</span>
<span style="font-family:KaiTi_GB2312;font-size:18px;"> public static void main(String[] args) { Tree tree = new Tree(); tree.TreeHtml(); }</span>
最近,因爲考試,看了數據結構 這本書。首先,我是在想,你們都用的這種方法,到底好在哪兒了,還有就是,爲何在咱們的數據庫設計中,樹的度的概念沒有體現出來。其次是,對於樹的遍歷,有非遞歸的方式,我想也許,我也能夠不用遞歸,就實現樹形結構的數據查找。因而乎,請看下文:數據庫設計
爲何我不想用遞歸:工具
1,通過查證,系統使用遞歸算法,須要系統堆棧處理。當樹的深度很大時,因爲系統支撐不住,會呈現死亡狀態。this
2,遞歸算法的運行效率較低,不管是耗費的計算時間仍是佔用的存儲空間都比非遞歸算法要多。spa
3,最爲直接的緣由:很長一段時間裏,我都不能理解遞歸算法,我總在想,可不能夠用我會的,我喜歡的 方式,去解決我面臨的問題?
遞歸的好處:
結構清晰,可讀性強,並且容易用數學概括法來證實算法的正確性,所以它爲設計算法、調試程序帶來很大方便。
事實證實,對於樹結構的數據搜索,徹底能夠不使用遞歸。我總算完成了我本身的夢想,終於,我能夠不用遞歸,也能夠實現樹結構的查找了。更爲高興的是,事實證實,採用非遞歸的方式,在我接觸到的項目中,它有更大的優點。
下一篇播客,介紹怎麼用非遞歸的方式查找樹結構的數據!至此,我好像以爲本身又變得不同了的感受,我把數據結構這本書的內容,徹底結合到本身的項目中,而且用這些東西,去改造去理解個人代碼。開心,不過還有圖,我不知道怎麼用的,關於圖,我想到了非關係型數據庫,再去驗證吧!