<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)  編輯  收藏

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


    網站導航:
     
    主站蜘蛛池模板: 亚洲毛片免费视频| 亚在线观看免费视频入口| 一个人在线观看视频免费| 亚洲一区中文字幕久久| 亚洲视频在线免费观看| 久久久久久亚洲AV无码专区| 污视频在线免费观看| 亚洲系列中文字幕| 久久久久久国产a免费观看黄色大片 | 久久综合九九亚洲一区| 永久免费av无码入口国语片| 亚洲精品高清国产一线久久| 无码人妻一区二区三区免费看| 亚洲国产精品热久久| 67194熟妇在线永久免费观看| 最新国产成人亚洲精品影院| 免费无码A片一区二三区| 国产亚洲精品国产福利在线观看| 亚洲高清偷拍一区二区三区 | 亚洲精彩视频在线观看| 18禁超污无遮挡无码免费网站国产 | 国内精品免费久久影院| 亚洲a一级免费视频| 久久久久久久91精品免费观看| 亚洲av永久中文无码精品| 亚洲欧洲精品成人久久曰影片| 巨胸喷奶水视频www免费视频| 久久亚洲春色中文字幕久久久| 成人爽A毛片免费看| 又长又大又粗又硬3p免费视频| 亚洲精品无码专区久久久| 亚洲w码欧洲s码免费| 亚洲av午夜电影在线观看 | 亚洲国产av无码精品| 久久免费视频精品| 亚洲中文无码亚洲人成影院| 亚洲情a成黄在线观看| 51视频精品全部免费最新| 久久精品熟女亚洲av麻豆 | 亚洲av日韩av高潮潮喷无码 | 亚洲中文无韩国r级电影 |