waysun一路陽光

          不輕易服輸,不輕言放棄.--心是夢的舞臺,心有多大,舞臺有多大。踏踏實實做事,認認真真做人。

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 ::  :: 管理 ::
            167 隨筆 :: 1 文章 :: 64 評論 :: 0 Trackbacks

          http://www.javaeye.com/topic/602979

          一篇不錯的文章,收藏了,呵呵!

          最近看到一個有意思的樹形結構,為每個節點添加了lftrgt兩個屬性。這樣查找該節點的子節點、查找該節點所有父節點,就不用去遞歸查詢,只需要用betweenand語句就可以實現。下面以創建一個欄目樹為例,以下是我的理解。

            一般來講,我們創建欄目樹的時候,大多只需要一個外鍵parentid來區分該節點屬于哪個父節點。數據庫的設計如下圖:
          這樣一來,

          1.查找該節點的所有子節點,則需要采用sql的遞歸語句:

           

          Sql代碼 復制代碼
          1. select * from tableName connect by prior id=sj_parent_id start with  id=1  

           

           (oracle 寫法,mysql目前不支持,如果mysql想查找樹形,可以利用存儲過程).

          2.查找該節點的父節點的sql遞歸語句:

           

          Sql代碼 復制代碼
          1. select * from tableName connect by prior sj_parent_id =id start with  id=1  

           

           如果數據量過大或者層次太多,那么這樣操作是會影響性能的。

           

            “任何樹形結構都可以用二叉樹來表示”。其實我們創建的欄目樹就是一個簡型的二叉樹。根據數據結構里面二叉樹的遍歷,再稍微修改下,將數據庫設計如下圖所示:

           


          這樣我們查找該節點的所有子節點,則只需要查找idlftrgt之間的所有節點即可。

          1.查找該節點的所有子節點的Sql語句為:

          <!--EndFragment-->

           

           

          <!--EndFragment-->

          Sql代碼 復制代碼
          1. select * from tb_subject s,tb_subject t where s.lft between t.lft and t.rgt and t.id=1  

           

          2.查找該節點的所有父節點的sql語句為:

          <!--EndFragment-->

          Sql代碼 復制代碼
          1. select s.* from tb_subject s,tb_subject t where s.lft<t.lft and (s.rgt-s.lft)>1 and s.rgt>t.rgt and t.id=1  

           

           下面來詳細講解下,怎么用java來實現這種算法。

          <!--EndFragment-->

           1. 新增節點

           新增節點比較簡單,基本步驟為

           A. 查找當前插入節點的父節點的lft

           B. 將樹形中所有lftrgt節點大于父節點左值的節點都+2

           C. 將父節點左值+1,左值+2分別作為當前節點的lftrgt

           因為項目中采用的是struts2+hibernate3.2+spring2.5的框架,代碼如下:

          <!--EndFragment-->

          Java代碼 復制代碼
          1. public boolean onSave(Object entity, Serializable id, Object[] state,   
          2.             String[] propertyNames, Type[] types) {   
          3.         if (entity instanceof HibernateTree) {   
          4.             HibernateTree tree = (HibernateTree) entity;   
          5.             Long parentId = tree.getParentId();   
          6.             String beanName = tree.getClass().getName();   
          7.             Session session = getSession();   
          8.             FlushMode model = session.getFlushMode();   
          9.             session.setFlushMode(FlushMode.MANUAL);   
          10.             Integer myPosition = new Integer(0);   
          11.             //查找父節點的左值   
          12.             if (parentId != null) {   
          13.                 String hql = "select b.lft from " + beanName   
          14.                         + " b where b.id=:pid";   
          15.                 myPosition = (Integer) session.createQuery(hql).setLong("pid",   
          16.                         parentId).uniqueResult();   
          17.             }   
          18.             //將樹形結構中所有大于父節點左值的右節點+2   
          19.             String hql1 = "update " + beanName   
          20.                     + " b set b.rgt = b.rgt + 2 WHERE b.rgt > :myPosition";   
          21.             //將樹形結構中所有大于父節點左值的左節點+2   
          22.             String hql2 = "update " + beanName   
          23.                     + " b set b.lft = b.lft + 2 WHERE b.lft > :myPosition";   
          24.             if (!StringUtils.isBlank(tree.getTreeCondition())) {   
          25.                 hql1 += " and (" + tree.getTreeCondition() + ")";   
          26.                 hql2 += " and (" + tree.getTreeCondition() + ")";   
          27.             }   
          28.             session.createQuery(hql1).setInteger("myPosition", myPosition)   
          29.                     .executeUpdate();   
          30.             session.createQuery(hql2).setInteger("myPosition", myPosition)   
          31.                     .executeUpdate();   
          32.             session.setFlushMode(model);   
          33.             //定位自己的左值(父節點左值+1)和右值(父節點左值+2)   
          34.             for (int i = 0; i < propertyNames.length; i++) {   
          35.                 if (propertyNames[i].equals(HibernateTree.LFT)) {   
          36.                     state[i] = myPosition + 1;   
          37.                 }   
          38.                 if (propertyNames[i].equals(HibernateTree.RGT)) {   
          39.                     state[i] = myPosition + 2;   
          40.                 }   
          41.   
          42.             }   
          43.             return true;   
          44.         }   
          45.         return false;   
          46.     }  

           

           2. 修改節點

            修改的時候比較麻煩,具體步驟為:

            在修改lftrgt之前,當前節點的父節點id已經改變

          a. 查出當前節點的左右節點(nodelftnodergt),并nodergt-nodelft+1 = span,獲取父節點的左節點parentlft

          b. 將所有大于parentlftlft(左節點)rgt(右節點)的值+span

          c. 查找當前節點的左右節點(nodelftnodergt),并parentlft-nodelft+1 = offset

          d. 將所有lft(左節點) between nodelft and nodergt的值+offset

          e. 將所有大于nodergtlft(左節點)rgt(右節點)的值-span

           Java代碼如下:

          <!--EndFragment-->

          Java代碼 復制代碼
          1. public void updateParent(HibernateTree tree, HibernateTree preParent,   
          2.             HibernateTree curParent) {   
          3.         if (preParent != null && preParent != null  
          4.                 && !preParent.equals(curParent)) {   
          5.             String beanName = tree.getClass().getName();   
          6.             // 獲得節點位置   
          7.             String hql = "select b.lft,b.rgt from " + beanName   
          8.                     + " b where b.id=:id";   
          9.             Object[] position = (Object[]) super.createQuery(hql).setLong(   
          10.                     "id", tree.getId()).uniqueResult();   
          11.             System.out.println(hql+"| id = "+tree.getId());    
          12.             int nodeLft = ((Number) position[0]).intValue();   
          13.             int nodeRgt = ((Number) position[1]).intValue();   
          14.             int span = nodeRgt - nodeLft + 1;   
          15.             // 獲得當前父節點左位置   
          16.             hql = "select b.lft from " + beanName + " b where b.id=:id";   
          17.             int parentLft = ((Number) super.createQuery(hql).setLong("id",   
          18.                     curParent.getId()).uniqueResult()).intValue();   
          19.   
          20.             System.out.println(hql+"| id = "+curParent.getId());   
          21.             // 先空出位置   
          22.             String hql1 = "update " + beanName + " b set b.rgt = b.rgt + "  
          23.                     + span + " WHERE b.rgt > :parentLft";   
          24.             String hql2 = "update " + beanName + " b set b.lft = b.lft + "  
          25.                     + span + " WHERE b.lft > :parentLft";   
          26.             if (!StringUtils.isBlank(tree.getTreeCondition())) {   
          27.                 hql1 += " and (" + tree.getTreeCondition() + ")";   
          28.                 hql2 += " and (" + tree.getTreeCondition() + ")";   
          29.             }   
          30.             super.createQuery(hql1).setInteger("parentLft", parentLft)   
          31.                     .executeUpdate();   
          32.             super.createQuery(hql2).setInteger("parentLft", parentLft)   
          33.                     .executeUpdate();   
          34.   
          35.             System.out.println(hql1+"| parentLft = "+parentLft);   
          36.             System.out.println(hql2+"| parentLft = "+parentLft);   
          37.                
          38.             // 再調整自己   
          39.             hql = "select b.lft,b.rgt from " + beanName + " b where b.id=:id";   
          40.             position = (Object[]) super.createQuery(hql).setLong("id",   
          41.                     tree.getId()).uniqueResult();   
          42.             System.out.println(hql+"| id = "+tree.getId());   
          43.             nodeLft = ((Number) position[0]).intValue();   
          44.             nodeRgt = ((Number) position[1]).intValue();   
          45.             int offset = parentLft - nodeLft + 1;   
          46.             hql = "update "  
          47.                     + beanName   
          48.                     + " b set b.lft=b.lft+:offset, b.rgt=b.rgt+:offset WHERE b.lft between :nodeLft and :nodeRgt";   
          49.             if (!StringUtils.isBlank(tree.getTreeCondition())) {   
          50.                 hql += " and (" + tree.getTreeCondition() + ")";   
          51.             }   
          52.             super.createQuery(hql).setParameter("offset", offset)   
          53.                     .setParameter("nodeLft", nodeLft).setParameter("nodeRgt",   
          54.                             nodeRgt).executeUpdate();   
          55.             System.out.println(hql+"| offset = "+offset+" | nodelft = "+nodeLft+" | nodergt = "+ nodeRgt);   
          56.             // 最后刪除(清空位置)   
          57.             hql1 = "update " + beanName + " b set b.rgt = b.rgt - " + span   
          58.                     + " WHERE b.rgt > :nodeRgt";   
          59.             hql2 = "update " + beanName + " b set b.lft = b.lft - " + span   
          60.                     + " WHERE b.lft > :nodeRgt";   
          61.             if (tree.getTreeCondition() != null) {   
          62.                 hql1 += " and (" + tree.getTreeCondition() + ")";   
          63.                 hql2 += " and (" + tree.getTreeCondition() + ")";   
          64.             }   
          65.             super.createQuery(hql1).setParameter("nodeRgt", nodeRgt)   
          66.                     .executeUpdate();   
          67.             super.createQuery(hql2).setParameter("nodeRgt", nodeRgt)   
          68.                     .executeUpdate();   
          69.             System.out.println(hql1+"| nodeRgt = "+nodeRgt);   
          70.             System.out.println(hql2+"| nodeRgt = "+nodeRgt);   
          71.                
          72.         }   
          73.     }  

           

           3. 刪除節點

           刪除節點也比較簡單,具體步驟為:

           A. 查找要刪除節點的lft

           B. 將所有lftrgt大于刪除節點lft值的都-2

           Java代碼如下:

          <!--EndFragment-->

           

           

           

           

          <!--EndFragment-->
          Java代碼 復制代碼
          1. public void onDelete(Object entity, Serializable id, Object[] state,   
          2.             String[] propertyNames, Type[] types) {   
          3.         if (entity instanceof HibernateTree) {   
          4.             HibernateTree tree = (HibernateTree) entity;   
          5.             String beanName = tree.getClass().getName();   
          6.             Session session = getSession();   
          7.             FlushMode model = session.getFlushMode();   
          8.             session.setFlushMode(FlushMode.MANUAL);   
          9.         //查找要刪除的節點的左值   
          10.             String hql = "select b.lft from " + beanName + " b where b.id=:id";   
          11.             Integer myPosition = (Integer) session.createQuery(hql).setLong(   
          12.                     "id", tree.getId()).uniqueResult();   
          13. //將所有大于刪除節點左值的rgt都-2   
          14.             String hql1 = "update " + beanName   
          15.                     + " b set b.rgt = b.rgt - 2 WHERE b.rgt > :myPosition";   
          16. //將所有大于刪除節點左值的lft都-2   
          17.             String hql2 = "update " + beanName   
          18.                     + " b set b.lft = b.lft - 2 WHERE b.lft > :myPosition";   
          19.             if (tree.getTreeCondition() != null) {   
          20.                 hql1 += " and (" + tree.getTreeCondition() + ")";   
          21.                 hql2 += " and (" + tree.getTreeCondition() + ")";   
          22.             }   
          23.             session.createQuery(hql1).setInteger("myPosition", myPosition)   
          24.                     .executeUpdate();   
          25.             session.createQuery(hql2).setInteger("myPosition", myPosition)   
          26.                     .executeUpdate();   
          27.             session.setFlushMode(model);   
          28.         }   
          29.     }  

          樹形結構_算法.rar (37 KB)

          posted on 2010-03-01 09:07 weesun一米陽光 閱讀(4720) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 巩义市| 潮安县| 石嘴山市| 时尚| 太仓市| 都匀市| 张掖市| 石景山区| 仁化县| 蓝田县| 阿拉善盟| 卫辉市| 绵阳市| 栖霞市| 仁化县| 黄平县| 民权县| 兴山县| 娄烦县| 武威市| 阳山县| 北宁市| 青海省| 鹤峰县| 芜湖县| 双柏县| 桓台县| 军事| 朝阳县| 南宁市| 施秉县| 阜阳市| 台前县| 弥勒县| 洛川县| 苏尼特右旗| 台中县| 台中市| 青川县| 台北市| 柞水县|