[ASP]無限級分類的簡單演算法實現及代碼重點講解http://bbs.blueidea.com/thread-1982151-1-1.html

來源:互聯網
上載者:User
一、前言
       很多情況下二級分類已經不能滿足需要了,而網上可用的多級分類的例子實在是不好找,故有此文。

http://bbs.blueidea.com/viewthread.php?tid=1182243

大家可以先看這個,它介紹了一種超級好的演算法,反正我是看不大懂呀。

二、我們要解決的問題:
1、 分類演算法常常表現為樹的表示和遍曆問題。那麼,請問:如果用資料庫中的一個Table來表達樹型分類,應該有幾個欄位?
2、 如何快速地從這個Table恢複出一棵樹;
3、 如何判斷某個分類是否是另一個分類的子類;
4、 如何尋找某個分類的所有產品;
5、 如何產生分類所在的路徑。
6、 如何新增分類;

三、遞迴實現的優點與缺點
       該怎麼實現多級分類呢?
       估計首先想到的都是遞迴,實現簡單,在指定節點(就是分類,下同)下添加、修改、刪除節點都不是問題,
而且節點移動實現起來也不是很難,只是要注意移動目的父節點不能是當前節點的父節節點(等於沒移動),也不能是當前節點的子節點(類似於window檔案夾,一個檔案夾是不能移動到自己的字檔案夾裡的)。
       但是最愁人的是搜尋指定節點下的東西,怎麼辦?也就是上面的問題3。記住,這是要包括所有子節點的,難道還去遞迴嗎?

四、介紹下我的簡單演算法(是我所用的,不是我發明的)
       以常見的商品系統為例。
       4.1 表結構
              [1]分類表,T_Sort,表結構一所示。其中sortPath儲存的是節點路徑,這是個重點。
              [2]商品表,T_Product,表結構二所示。
[center]圖一
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" alt="" src="http://mytju.com/temp/tech/t_sort.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>

圖二
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" alt="" src="http://mytju.com/temp/tech/t_product.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>
[/center]
       4.2 演算法簡要說明
              [1]parentID儲存的自然是節點的父節點,如果一個節點的parentID=0時,認為它是一級分類。
              [2]一個節點的sortPath為它的父節點的sortPath+自己的sortID+","。如sortID=32的節點的父節點是節點21,節點21的sortPath是"0,21,",那麼節點32的sortPath就是"0,21,32,"。有點繞,看圖三清楚啦。可能你想不通為啥最後要多個逗號啊,後面你就明白啦。所有節點的sortPath的左邊兩位都是"0,",因為它們都在根節點下。一個節點的sortPath一定包含在它的子節點的sortPath中。
[center]
圖三
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" alt="" src="http://mytju.com/temp/tech/t_sort2.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>[/center]
       4.3 代碼重點講解。
              這裡以我們要實現的功能為例講解。
              [1]添加節點
                     <1>選擇父節點,可以是根節點,或是下級所有節點(最好列出一個樹型菜單讓使用者選擇,別愁,可以實現),其實就是選擇parentID。
                     <2>如果parentID=0,那麼上級sortPath="0,",如果parentID<>0,那麼到表T_Sort根據parentID取得上級sortPath。
                     <3>給T_Sort新增記錄,sortPath=上級sortPath +新記錄的sortID +","。
                     <4>範例代碼見圖4、圖5。其中noRecord,closeRs(),showMsg(),closeConn()都是我定義的Function或Sub,它們的功能都是顧名思義的,我就不說了。注意一下,如果你用MS SQL,代碼略有不同。我也很奇怪MS SQL時,addNew後,這個新的自動編號可以輸出,但是和字元一串連就沒有了。各位如果知道為什麼,還請相告。
[center]
圖四
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" alt="" src="http://mytju.com/temp/tech/addsort.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>

圖五
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" alt="" src="http://mytju.com/temp/tech/addsort_mssql.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>[/center]
              [2]修改節點
                     節點的屬性只有一個名字而已,直接update就可以了,就不說了。
              [3]刪除節點
                     <1>選擇節點
                     <2>如果parentID=0,報錯,根節點不能刪除。
                     <3>刪除該節點及所有子節點。你可能想是不是很麻煩啊,哈哈,其實我只用了一個SQL語句就搞定啦。

[Copy to clipboard] [ - ]

CODE:

(Access)sql="delete from T_Sort where Instr(sortPath,',"&parentID&",')>0"

[Copy to clipboard] [ - ]

CODE:

(MS SQL)sql="delete from T_Sort where CHARINDEX(',"&parentID&",',sortPath)>0"

本演算法的精華就在這裡啦,仔細想想吧,sortPath最後那個逗號的作用也在這裡啦。
                     <4>刪除上述所有節點下的商品。同上,表名不同而已。

[Copy to clipboard] [ - ]

CODE:

(Access)sql="delete from T_Product where Instr(sortPath,',"&parentID&",')>0"

[Copy to clipboard] [ - ]

CODE:

(MS SQL)sql="delete from T_Product where CHARINDEX(',"&parentID&",',sortPath)>0"

<5>範例代碼見圖6。MS SQL的代碼就不貼了。
[center]
圖六
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" alt="" src="http://mytju.com/temp/tech/delsort.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>[/center]
              [4]移動節點
                     痛點哦,睜大眼睛仔細看。
                     <1>選擇要移動的節點parentID,選擇目的節點toParentID(也就是把當前節點放到誰的下面)。
                     <2>如果parentID=0報錯,根節點不能移動。
                     <3>如果toParentID=parentID,這是要把自己放到自己下面,報錯。
                     <4>根據parentID,取得它的sortPath,我們叫它fromPath。
                     <5>如果toParentID=0,那麼toPath="0,",如果toParentID<>0,取得它的sortPath,叫它toPath。
                     <6>如果toParentID等於要移動節點的父節點,不需要移動,報錯。判斷方法是看toPath & parentID &","是否等於fromPath。
                     <7>如果toParentID是要移動節點的子節點,不能移動,報錯。判斷方法是看Instr(toPath,fromPath)是否大於0。
                     <8>組合要移動節點的新sortPath,也就是newPath=toPath & parentID &","。
                     <9>更新要移動節點及其所有子節點的sortPath()。如"0,2,3,5,"移動到"0,1,"下,那麼新的sortPath就是"0,1,5,"了(想想,對吧)。而"0,2,3,5,"的所有子節點的左半部分都是"0,2,3,5,",那麼只要把"0,2,3,5,"替換成"0,1,5,"就行了。

[Copy to clipboard] [ - ]

CODE:

(Access)sql="update T_Sort set sortPath='"&newPath&"'+Mid(sortPath,Len('"&fromPath&"')+1) where Instr(sortPath,'"&fromPath&"')>0"

[Copy to clipboard] [ - ]

CODE:

(MS SQL)sql="update T_Sort set sortPath=replace(sortPath,'"&fromPath&"','"&newPath&"') where CHARINDEX[('"&fromPath&"',sortPath)>0"

因為Access好像沒有內建repalce函數,所以麻煩了一些。
                     <10>更新要移動節點的parentID。直接update就行啦。
                     <11>商品是跟隨分類走的,所以商品的parentID不用更新,只要更新它的sortPath就行了。語句同<9>,只是表名換成T_Product。
                     <12>範例代碼見圖7。MS SQL的代碼只有上面2個SQL語句不同,不貼了。
[center]
圖七
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" style="WIDTH: 735px; CURSOR: hand; HEIGHT: 738px" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" height=738 alt="Click here to open new window
CTRL+Mouse wheel to zoom in/out" src="http://mytju.com/temp/tech/movesort.gif" width=716 onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0 resized="true">[/center]
              [5]前台分類瀏覽商品
                     前台一般都不會把所有類別一下子都列出來,都是分級瀏覽的,一層一層的看。我們要做的只是瀏覽一個分類時,把它的下級分類列出來。
                     <1>取直接子類別,很簡單啦。

[Copy to clipboard] [ - ]

CODE:

sql="select sortID,sortName from T_Sort where parentID="&sortID

就行啦。
                     <2>一般我們都會顯示一個當前位置,就是分類所在的路徑,怎麼辦呢?難道去遞迴查詢嗎?當然不,我這裡用了一個小技巧。
                     瀏覽某一個分類的時候,我們會有一個sortID,可以根據它從T_Sort取得sortPath....不說了,大家看示範代碼吧,不懂問我。
                     範例代碼見圖8。
[center]
圖八
screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.style.cursor='hand'; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" onclick="if(!this.resized) {return true;} else {window.open(this.src);}" alt="" src="http://mytju.com/temp/tech/browersort.gif" onload="if(this.width>screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoom in/out';}" border=0>[/center]
                     顯示的時候用

[Copy to clipboard] [ - ]

CODE:

<%for i=1 to UBound(myArray)
    response.write "-&gt; <a href='product.asp?sortID="&myArray(i)&"'>"&getValueByID(myArray(i),nameArray)&"</a>"
next%>

就OK了。getValueByID是我寫的一個Function,見後。
                     <3>顯示該類別及其所有子類別下的所有商品。

[Copy to clipboard] [ - ]

CODE:

sql="select * from T_Product where Instr(sortPath,',"&sortID&",')>0"

如果只顯示該類別下的商品,那麼就用parentID判斷就行了。
              [6]前台檢索商品
                     如果你的檢索表單不包含商品類別,那麼沒有什麼特殊的。如果有商品類別的話,也很簡單,SQL的where條件裡加一個

[Copy to clipboard] [ - ]

CODE:

"and Instr(sortPath,',"&sortID&",')>0"

就行了。
              [7]後台商品添加、修改
                     添加是要選擇所在的分類,這樣就可以得到sortID,並能取得它的sortPath,儲存到商品記錄就行了。
                     修改類似。
              [8]後台商品刪除
                     和分類不相關,直接根據productID刪除就可。
五、附加資訊
       目前還沒有拆分出來的代碼給大家(太麻煩),主要的東西都在上面啦。
       師傅領進門,修行在個人啦。

[Copy to clipboard] [ - ]

CODE:

'-----根據ID取得name的Sub-----------------
Function getValueByID(sortID,inArray)
    dim i
    if NOT IsArray(inArray) then
        getValueByID=""
        Exit Function
    end if
    for i=0 to UBound(inArray,2)
        if Cstr(sortID)=Cstr(inArray(0,i)) then
            getValueByID=inArray(1,i) '返回name
            Exit Function
        end if
    next
    getValueByID=""
End Function
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.