当前位置:编程学习 > asp >>

使用多中值排序基数实现大型树状结构

答案:     在“中值排序基数法实现树状结构”中,为了解决回复限制的问题,我们可以增加第二(三、四……)基数字段。
   其实在一般的BBS中,使用一个基数已经足够,因为一个贴子的回复太多或深度太大的时候,无论你的树状结构做得多好,由于屏幕的限制(显示折行),显示总会乱,因此不如象在《补充》一文中,达到一定深度或个数时,后面的贴子采用平行显示的方法,不过那部分已经不再是树状结构了。
   原理:在贴子显示的order by子句中,如果排序基数相同,则根据第二基数排序,从而避免树状结构限制。
  
  一、在BBS的内容表中再增加一个第二基数字段ordernumS,同第一基数一样,可为int或numeric,看需要定。
  
  这样在表中增加了四个冗余字段,rootid——用于记录根id,deep——用于记录回复的深度(为0时表示根贴),ordernum——第一排序基数,ordernumS——第二排序基数
  
  表forum与(只列与树状结构有关的字段):
  id rootid deep ordernum ordernumS
  其中id、rootid、deep均为int型(deep可为tinyint型),ordernum为int或float型,ordernumS(默认值为0)同ordernum。
  
  例:(在此为了简单,使用一个小的起始排序基数,且为int型,以清楚观察什么时候第二排序基数起作用)。
  (下面所说的排序均指按ordernum从小到大,ordernumS从小到大排序,即order by ordernum,ordernumS)
  (下面所说的精度为后贴与前贴的ordernum的差,精度标记指的是这个差大于某个值这个条件,比如(后贴的ordernum-前贴的ordernum)>1)
  
  id rootid deep ordernum ordernumS
  1 0 0 0 0
  2 1 1 8 0
  _____________________________________
  3 1 1 4 0 回复第1贴,第一基数取1、2贴的第一基数中值即(0+8)/2=4
  
  排序后结果为:
  id rootid deep ordernum ordernumS
  1 0 0 0 0
  3 1 1 4 0
  2 1 1 8 0
  _____________________________________
  4 1 2 6 0 回复第3贴,第一基数取3、2的第一基数中值即(4+8)/2
  
  排序后结果为:
  id rootid deep ordernum ordernumS
  1 0 0 0 0
  3 1 1 4 0
  4 1 2 6 0
  2 1 1 8 0
  _____________________________________
  5 1 3 7 0 回复第4贴,第一基数取4、2的第一基数中值即(6+8)/2
  
  排序后的结果为:
  id rootid deep ordernum ordernumS
  1 0 0 0 0
  3 1 1 4 0
  4 1 2 6 0
  5 1 3 7 0
  2 1 1 8 0
  _____________________________________
  6 1 3 6 8 回复第4贴,第一基数取4、5的第一基数中值即(6+7)/2,因是int型,被截成了6
   此时精度标记(暂设为1)已经不满足(即5的第一基数与4的第一基数差不大于1,为1),此时在父贴的第二基数加上一起始值作为新贴的第二基数
  排序后的结果为:
  id rootid deep ordernum ordernumS
  1 0 0 0 0
  3 1 1 4 0
  4 1 2 6 0
  6 1 3 6 8
  5 1 3 7 0
  2 1 1 8 0
  _____________________________________
  7 1 3 6 4 回复第4贴,第一基数取4、6的第一基数中值即(6+6)/2=6
   此时精度标记(暂设为1)已经不满足(即4的第一基数与6的第一基数差不大于1,为0),此时第二基数取6、4的第二基数中值(0+8)/2=4
  
  
  排序后的结果为:
  id rootid deep ordernum ordernumS
  1 0 0 0 0
  3 1 1 4 0
  4 1 2 6 0
  7 1 3 6 4
  6 1 3 6 8
  5 1 3 7 0
  2 1 1 8 0
  
  这样排序基数ordernum、ordernumS与回复深度deep一起就实现了如下的树状结构:
  id
  1
   3
   4
   7
   6
   5
  2
  
  在这可以看到,第一基数ordernum与第二基数ordernumS以及深度deep实现了树状结构!
  
  
  二、插入的实现(如何确定排序基数,下面所指贴子均为同一根下的子贴)
  (一)根第一基数ordernum定为0
  (二)所有贴子第二基数默认为0
  (三)第一条回复贴子基数定为2的整数次幂(如65536=2^16,可取更大的数)
  (四)回复树中最后一条贴子时,基数取最后一贴的基数ordernum再加上2的整数次幂(同上)
  (五)当第一基数差大于精度标记时,第一基数取中值,忽略第二基数(为0)
  (五)当第一基数差等于精度标记时,第一基数取回复贴的第一基数,第二基数取回复贴的第二基数加上基数起始值
  (六)当第一基数差小于精度标记时,第一基数取回复贴的第一基数,第二基数取前后贴的第二基数中值
  
   如果要使用parentid字段,则更新相关的parentid,这里不再讨论。
  
  三、删除的实现
  
   删除贴子(剪枝)时,当:
   (一)要删除的是根贴时,将整个树删除即可
   (二)要删除的是子枝时,只需按ordernum和ordernumS排序,找出从指定要删除的贴子开始的所有贴子(使用条件rootid=@rootid and (ordernum>@ordernum or ordernum=@ordernum and ordernumS>=@ordernumS)),从上到下逐个判断深度是不是增加,如果增加则予以删除。一旦发现深度等于或小于要删贴子(枝顶)的深度,则马上退出删除。
   如上例子中,要删除4贴一个分枝,只需找出4后面的所有贴子,然后逐个往下判断,如果深度大小4贴的深度则删除,而一旦遇到深度等于或者小于4贴深度,则马上退出删除。结果是4、7、6、5满足条件,这就是我们要删除的子枝。
   如果要增加parentid字段,则需判断共删除了多少个贴子,以例更新有关的parentid字段。
   为了方便和提高速,使用操作API光标的存储过程来进行。
  
  四、显示的实现
   只需执行select * from forum order by rootid+id-sign(rootid)*id desc,ordernum,ordernumS,然后结合deep就可实现树状的显示。
  
  
  五、具体实现方法(以存储过程为例)
  
  加贴存储过程:(ordernum和ordernumS使用int型,设精度标记为1)
  
  CREATE PROCEDURE [add] @keyid int,@message varchar(50) OUTPUT ———keyid为回复的贴子id号,如果是新贴则为0,@message为出错信息
  AS
   IF (@keyid=0)
   INSERT INTO forum (rootid,deep,ordernum,ordernumS……) values(0,0,0,0……)
   ELSE
   BEGIN
   DECLARE @rootid int,@id int,@deep int,@begnum int,@endnum intt,@begS int,endS int,@ordernum int,@ordernumS int
   SELECT @rootid=0,@id=0,@deep=0,@begnum=0,@endnum=0,@ordernum=0,@ordernumS=0,@begS=0,@endS=0
   SELECT @rootid=rootid,@id=id,@begnum=ordernum,@begs=begs,@deep=deep from forum where id=@keyid
   IF (@id=0)
   BEGIN
   SELECT @message=''要回复的贴子已经被删除!''
   return
   END
   ELSE
   BEGIN
   IF (@root

上一个:不用递归实现树形结构的一种方法
下一个:浅谈Asp程序的编写和调试——给初学者

CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,