<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    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一米陽光 閱讀(4718) 評論(0)  編輯  收藏

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


    網站導航:
     
    主站蜘蛛池模板: 精品一区二区三区免费毛片| 亚洲福利视频网址| 成人婷婷网色偷偷亚洲男人的天堂| 国产18禁黄网站免费观看| 亚洲欧洲校园自拍都市| 国产成人精品免费视频大| 亚洲日本中文字幕| 国产激情免费视频在线观看| 亚洲AV福利天堂一区二区三| 亚洲视频在线观看免费| 亚洲成人免费网站| 成年女人毛片免费播放人| 亚洲AV无码国产精品永久一区| 亚洲一区二区三区免费| 日批日出水久久亚洲精品tv| 四虎影视永久在线精品免费| 国产亚洲成归v人片在线观看| 亚洲乱码在线播放| 免费看韩国黄a片在线观看| 亚洲爆乳精品无码一区二区| 又爽又高潮的BB视频免费看| 一二三区免费视频| 久久精品国产亚洲| 欧美在线看片A免费观看| 国产亚洲一卡2卡3卡4卡新区| 最近高清中文字幕免费| 亚洲AV无码久久久久网站蜜桃| v片免费在线观看| 亚洲国产另类久久久精品黑人| 亚洲综合av一区二区三区不卡 | 久久er国产精品免费观看8| 无码国产亚洲日韩国精品视频一区二区三区 | 亚洲国产成人久久精品app| 无限动漫网在线观看免费| 无码天堂va亚洲va在线va| 亚洲日韩av无码| 免费不卡视频一卡二卡| 无码毛片一区二区三区视频免费播放 | 午夜影视在线免费观看| 一级毛片免费在线播放| 亚洲理论片中文字幕电影|