jsp實現樹狀結構

來源:互聯網
上載者:User

首先,介紹一下樹狀結構在DB中的儲存。

使用二維表,如,儲存樹狀結構:

現在,我們的目標是想要把這一樹狀結構表示成:

由可以看出它們之間含有一種層級關係,查看原始碼,如下:

現在,演算法的思路是,先將樹狀結構按照list的順序排列出來,這個順序其實就是去掉了UL和LI標籤的順序,如:

要實現這個順序其實很簡單。

再來看看我們的樹

abcdef其實就是這顆樹的先序遍曆的結果。

那麼,如果現在我們只有一張二維表,那麼我們要怎樣產生這個先序遍曆的結果呢?(不使用遞迴)

觀察這張二維表:

node到fatherNode是一對一映射,而fatherNode到node之間則是一對多映射。

也就是說我們可能不太容易知道某個節點的兄弟節點(需要先確定父節點,再通過父節點query兄弟節點),但是確定某個節點的子節點是非常容易的。

如,節點a的所有子節點,只要query fatherNode=a即可。

因此,我們可以使用廣搜的思想來解決這個問題。

廣搜就是先遍曆離根最近的第一層節點,將這些節點放入queue中,然後從queue頭不斷取出節點,再遍曆這個節點的所有子節點,並將其子節點放入queue的隊尾,依次下去,知道所有節點都遍曆到為止。

拿我們的樹來說,就是

但是,如果直接用廣搜這個演算法的話,我們得到的序列是:

abdcef

與我們所期待的不同。

所以,改進一下該演算法。

為了儲存我們的結構,建立一個列表。現在,我們就有兩個列表了,一個是廣搜用的queue,另一個是儲存結果的list。

當廣搜每摘掉一個頭元素,並將該元素的子節點放入queue中時,就在儲存的list中的相應位置插入這些子節點們。那麼相應位置是哪裡呢?就是被摘掉的這個頭元素。

例如,現在queue的形態為 “a” ,那麼現在要做的操作是把queue的頭,a元素摘掉,並且將其子節點"b d"加入queue中,與此同時,在list中尋找到a的位置,並將“b d”添加到其後面。此時,queue的形態變為"b d",而list則變為"a b d"。重複此步驟,現在摘掉queue中的頭元素,即b,並且將其子節點(c)放入queue尾部,同時在list的b元素後面添加b的子節點(c),此時,queue的形態變為“d c”,而list的形態變為“a b c d”。依照此方式一直進行到廣搜結束,即進行到queue為空白。

該演算法結束時,就可以得到 a b c d e f  這一我們希望見到的序列了。

但是,這一序列丟失了一項很重要的資訊,就是層次資訊。

所以,再對演算法進行一下改進,我們引入一個結構體

<node, level>

使用 level 屬性來記錄某個節點所處的層次。

那麼level這個屬性在什麼時候進行賦值呢?

在將某個元素的子項目插入list中時。

如何賦值呢?

這個問題很簡單,因為是為某個元素插入子項目,因此,被插入的這些元素的level相當於其父節點的 level + 1

所以,list最後就變成了這樣一個結構:

node list的順序 “abcdef”,以及其level屬性都是必須的。

現在,我們既知道了節點的順序,也知道了節點中各個點的關係,因此就可以構建又ul和li表示的樹狀結構了。

我們再觀察一下原始碼:

發現,

(1)當level增大時,就會出現一個<ul>標籤。

(2)當level減小時,就會出現</ul>標籤,而</ul>標籤的數量與level減小的程度有關,即減小的level是N,就應該出現N個</ul>標籤。

(3)對於每一個list中的item,都由一個<li></li>標籤對包圍。

由上述規則,我們就可以寫出如下程式:

Stack<String> stack = new Stack<String>();        String item = "</ul>";        String res = "";                ArrayList<SightLevelPair>  list = this.sightTree.getList();                int lastLevel = 0;        int currLevel = 0;                if(list.size() != 0){                        Iterator<SightLevelPair> iter = list.iterator();                        while(iter.hasNext()){                                SightLevelPair pair = iter.next();                                currLevel = pair.getLevel();                                if(currLevel > lastLevel){                    res += "<ul>";                    stack.push(item);                }else if(currLevel < lastLevel){                    int delta = lastLevel - currLevel;                                        while(delta > 0){                        res += stack.pop();                        --delta;                    }                                    }                                res += "<li>" + pair.getSight().getSightName() + "</li>";                lastLevel = currLevel;            }                        while(0 != stack.size()){                res += stack.pop();            }        }

可以看到程式中有一個stack,它是用來儲存“</ul>”字串的。每當出現一個level增加時,就在最終在字串後加入一個“<ul>”,同時,將一個“</ul>”壓入stack中,並且在遇到level減少時,將相應數量的"</ul>"拋出。

結果還是很理想的:

產生這個樹用了自訂標籤,即定義了一個SimpleTagSupport的子類,用來處理自訂標籤。

製作自訂標籤的方法【在此】。

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.