锁定老帖子 主题:java树形结构 算法
精华帖 (2) :: 良好帖 (8) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-02-25
最后修改:2010-02-25
最近看到一个有意思的树形结构,为每个节点添加了lft和rgt两个属性。这样查找该节点的子节点、查找该节点所有父节点,就不用去递归查询,只需要用between、and语句就可以实现。下面以创建一个栏目树为例,以下是我的理解。 一般来讲,我们创建栏目树的时候,大多只需要一个外键parentid来区分该节点属于哪个父节点。数据库的设计如下图:
1.查找该节点的所有子节点,则需要采用sql的递归语句:
(oracle 写法,mysql目前不支持,如果mysql想查找树形,可以利用存储过程).
2.查找该节点的父节点的sql递归语句:
如果数据量过大或者层次太多,那么这样操作是会影响性能的。
“任何树形结构都可以用二叉树来表示”。其实我们创建的栏目树就是一个简型的二叉树。根据数据结构里面二叉树的遍历,再稍微修改下,将数据库设计如下图所示:
1.查找该节点的所有子节点的Sql语句为: <!--EndFragment--> 2.查找该节点的所有父节点的sql语句为: <!--EndFragment--> 下面来详细讲解下,怎么用java来实现这种算法。 1. 新增节点 新增节点比较简单,基本步骤为 A. 查找当前插入节点的父节点的lft值 B. 将树形中所有lft和rgt节点大于父节点左值的节点都+2 C. 将父节点左值+1,左值+2分别作为当前节点的lft和rgt 因为项目中采用的是struts2+hibernate3.2+spring2.5的框架,代码如下: <!--EndFragment--> 2. 修改节点 修改的时候比较麻烦,具体步骤为: 在修改lft和rgt之前,当前节点的父节点id已经改变 a. 查出当前节点的左右节点(nodelft、nodergt),并nodergt-nodelft+1 = span,获取父节点的左节点parentlft b. 将所有大于parentlft的lft(左节点)、rgt(右节点)的值+span c. 查找当前节点的左右节点(nodelft、nodergt),并parentlft-nodelft+1 = offset d. 将所有lft(左节点) between nodelft and nodergt的值+offset e. 将所有大于nodergt的lft(左节点)、rgt(右节点)的值-span Java代码如下: <!--EndFragment--> 3. 删除节点 删除节点也比较简单,具体步骤为: A. 查找要删除节点的lft值 B. 将所有lft和rgt大于删除节点lft值的都-2 Java代码如下:
<!--EndFragment-->
<!--EndFragment-->
<!--EndFragment-->
<!--EndFragment-->
<!--EndFragment--> 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-02-26
很好,很强大,以前没想过还可以这样,谢谢啦,收下
|
|
返回顶楼 | |
发表时间:2010-02-26
恕我愚昧 请问lft和rgt两个属性分别记录的是?
|
|
返回顶楼 | |
发表时间:2010-02-26
最后修改:2010-02-26
还有一个问题:你的id是自增长编号么?
如何保证,between lft 和 rgt 不会包含兄弟的子节点啊? 1 / \ 2 3 / \ / 4 5 6 / 7 2节点的lft和rgt分别是? |
|
返回顶楼 | |
发表时间:2010-02-26
最后修改:2010-02-26
|
|
返回顶楼 | |
发表时间:2010-02-26
andsofish 写道 恕我愚昧 请问lft和rgt两个属性分别记录的是?
在项目中并没有什么实际的意义。只是作为一个标识来方便我们查找。 |
|
返回顶楼 | |
发表时间:2010-02-26
抛出异常的爱 写道 http://intelligent-enterprise.informationweek.com/001020/celko.jhtml;jsessionid=D4NGPOGZWDQZPQE1GHPSKH4ATMY32JVN?_requestid=402826
牛叉树...就是加 减 节点时有点柴废 呵呵。。欢迎多多指教。 |
|
返回顶楼 | |
发表时间:2010-02-26
andsofish 写道 还有一个问题:你的id是自增长编号么?
如何保证,between lft 和 rgt 不会包含兄弟的子节点啊? 1 / \ 2 3 / \ / 4 5 6 / 7 2节点的lft和rgt分别是? 这个id是数据库的主键,不一定是自动增长的,根据自己选择的数据库类型来定,只要唯一就可以了。 “如何保证,between lft 和 rgt 不会包含兄弟的子节点啊?”这个问题,查询的sql语句我已经给出来了,你可以测试一下。 1 A 14 / \ 2 B 9 10 C 13 / \ \ 3 D 6 7 E 8 11 F 12 / 4 G 5 其中A、B、C等字母代表节点,而数字分别代表lft和rgt,比如A的lft=1,rgt=14 |
|
返回顶楼 | |
发表时间:2010-02-26
最后修改:2010-02-26
|
|
返回顶楼 | |
发表时间:2010-02-26
看起来好像很不错,还没细细研究,我想问问:根据你的说明 lft 和 rgt 只是方便我们解决递归查找性能问题的2个属性,那它到底记录什么?当我增加一个节点,它们的值分别怎么赋值?从根节点开始说吧 ,我比较笨,呵呵,谢谢。
|
|
返回顶楼 | |