[TREE]采用左右值编码来存储无限分级树形结构的数据库表设计

合集下载

树形结构的数据库设计

树形结构的数据库设计

树形结构的数据库表Schema设计程序设计过程中,我们常常用树形结构来表征某些数据的关联关系,如企业上下级部门、栏目结构、商品分类等等,通常而言,这些树状结构需要借助于数据库完成持久化。

然而目前的各种基于关系的数据库,都是以二维表的形式记录存储数据信息,因此是不能直接将Tree存入DBMS,设计合适的Schema及其对应的CRUD算法是实现关系型数据库中存储树形结构的关键。

理想中树形结构应该具备如下特征:数据存储冗余度小、直观性强;检索遍历过程简单高效;节点增删改查CRUD 操作高效。

无意中在网上搜索到一种很巧妙的设计,原文是英文,看过后感觉有点意思,于是便整理了一下。

本文将介绍两种树形结构的Schema设计方案:一种是直观而简单的设计思路,另一种是基于左右值编码的改进方案。

一、基本数据本文列举了一个食品族谱的例子进行讲解,通过类别、颜色和品种组织食品,树形结构图如下:二、继承关系驱动的Schema设计对树形结构最直观的分析莫过于节点之间的继承关系上,通过显示地描述某一节点的父节点,从而能够建立二维的关系表,则这种方案的Tree表结构通常设计为:{Node_id,Parent_id},上述数据可以描述为如下图所示:这种方案的优点很明显:设计和实现自然而然,非常直观和方便。

缺点当然也是非常的突出:由于直接地记录了节点之间的继承关系,因此对Tree的任何CRUD操作都将是低效的,这主要归根于频繁的“递归”操作,递归过程不断地访问数据库,每次数据库IO都会有时间开销。

当然,这种方案并非没有用武之地,在Tree规模相对较小的情况下,我们可以借助于缓存机制来做优化,将Tree的信息载入内存进行处理,避免直接对数据库IO操作的性能开销。

三、基于左右值编码的Schema设计在基于数据库的一般应用中,查询的需求总要大于删除和修改。

为了避免对于树形结构查询时的“递归”过程,基于Tree的前序遍历设计一种全新的无递归查询、无限分组的左右值编码方案,来保存该树的数据。

java树形结构表设计方案

java树形结构表设计方案

java树形结构表设计方案全文共四篇示例,供读者参考第一篇示例:一、背景介绍在软件开发中,树形结构是一种常见的数据结构,它能够以层次关系来表示数据元素之间的结构。

在实际开发中,树形结构通常用在类似组织结构、目录结构、分类信息等场景中。

而在Java中,我们可以利用树形结构来设计数据库表,以达到更高效的数据存储和管理目的。

二、设计方案1. 数据表设计我们可以通过建立两张表来实现树形结构的存储:一张是节点表,另一张是关系表。

节点表用于存储树形结构中的各个节点信息,包括节点ID、节点名称、父节点ID等相关信息;关系表用于存储节点之间的关系,即父子关系。

节点表的设计如下:```CREATE TABLE node (node_id INT PRIMARY KEY,node_name VARCHAR(50),parent_id INT);```2. 数据操作在设计好表结构后,我们可以通过一些字段来操作树形结构数据。

可以通过根节点的ID来获取整棵树的信息,或者通过节点的ID来获取其父节点和子节点的信息。

我们可以利用递归算法来实现对树形结构的操作。

要获取特定节点的所有子节点,可以通过以下伪代码实现:```function getChildren(node_id) {List<Node> children = new ArrayList<>();for (Node node : nodes) {if (node.parent_id == node_id) {children.add(node);children.addAll(getChildren(node.node_id));}}return children;}```3. 查询优化在处理树形结构数据时,由于节点之间存在父子关系,可能会出现多层嵌套查询的情况。

为了提高查询效率,我们可以采用一些优化措施,例如建立索引、使用缓存等。

对于查询来说,我们可以借助数据库的索引功能来加快查询速度。

TREE采用左右值编码来存储无限分级树形结构的数据库

TREE采用左右值编码来存储无限分级树形结构的数据库

采用左右值编码来存储无限分级树形结构的数据库表设计之前我介绍过一种按位数编码保存树形结构数据的表设计方法,详情见:浅谈数据库设计技巧(上)该设计方案的优点是:只用一条查询语句即可得到某个根节点及其所有子孙节点的先序遍历。

由于消除了递归,在数据记录量较大时,可以大大提高列表效率。

但是,这种编码方案由于层信息位数的限制,限制了每层能所允许的最大子节点数量及最大层数。

同时,在添加新节点的时候必须先计算新节点的位置是否超过最大限制。

上面的设计方案必须预先设定类别树的最大层数以及最大子节点数,不是无限分级,在某些场合并不能采用,那么还有更完美的解决方案吗?通过google的搜索,我又探索到一种全新的无递归查询,无限分级的编码方案——左右值。

原文的程序代码是用php写的,但是通过仔细阅读其数据库表设计说明及相关的sql语句,我彻底弄懂了这种巧妙的设计思路,并在这种设计中新增了删除节点,同层平移的需求(原文只提供了列表及插入子节点的sql语句)。

下面我力图用比较简短的文字,少量图表,及相关核心sql语句来描述这种设计方案:首先,我们弄一棵树作为例子:商品|---食品| |---肉类| | |--猪肉| |---蔬菜类| |--白菜|---电器|--电视机|--电冰箱select count(*) from tree where lft <= 2 and rgt >= 11为了方便列表,我们可以为tree表建立一个视图,添加一个层数列,该类别的层数可以写一个自定义函数来计算。

该函数如下:CREATE FUNCTION dbo.CountLayer(@type_id int)RETURNS intASbegindeclare@result intset@result=0declare@lft intdeclare@rgt intif exists (select1from tree where type_id=@type_id)beginselect@lft=lft,@rgt=rgt from tree where type_id=@type_idselect@result=count(*) from tree where lft <=@lft and rgt >=@rgtendreturn@resultendGO然后,我们建立如下视图:CREATE VIEW dbo.TreeViewASSELECT type_id, name, lft, rgt, dbo.CountLayer(type_id) AS layer FROM dbo.tree ORDE R BY lftGO()AS declare declare ifgo假定我们要在节点“肉类”下添加一个子节点“牛肉”,该树将变成:1商品18+2+--------------------------------------------+2食品11+2 12+2电器17+2+-----------------+ +-------------------------+3肉类6+2 7+2蔬菜类10+2 13+2电视机14+2 15+2电冰箱16+2 +-------------+4猪肉5 6牛肉78+2白菜9+2看完上图相应节点左右值的变化后,相信大家都知道该如何写相应的sql脚本吧?下面我给出相对完整的插入子节点的存储过程:CREATE PROCEDURE[dbo].[AddSubNodeByNode](@type_id int,@name varchar(50))ASdeclare@rgt intif exists (select1from tree where type_id=@type_id)beginSET XACT_ABORT ONBEGIN TRANSACTIONselect@rgt=rgt from tree where type_id=@type_idupdate tree set rgt=rgt+2where rgt>=@rgtupdate tree set lft=lft+2where lft>=@rgtinsert into tree (name,lft,rgt) values (@name,@rgt,@rgt+1)COMMIT TRANSACTIONSET XACT_ABORT OFFend然后,我们删除节点“电视机”,再来看看该树会变成什么情况:1商品20-2+-----------------------------------+2食品13 14电器19-2+-----------------+3肉类8 9蔬菜类12 17-2电冰箱18-2+----------+4猪肉5 6牛肉7 10白菜11相应的存储过程如下:CREATE PROCEDURE[dbo].[DelNode]@type_id intASdeclare@lft intdeclare@rgt intif exists (select1from tree where type_id=@type_id)beginSET XACT_ABORT ONBEGIN TRANSACTIONselect@lft=lft,@rgt=rgt from tree where type_id=@type_iddelete from tree where lft>=@lft and rgt<=@rgtupdate tree set lft=lft-(@rgt-@lft+1) where lft>@lftupdate tree set rgt=rgt-(@rgt-@lft+1) where rgt>@rgtCOMMIT TRANSACTIONSET XACT_ABORT OFFEnd注意:因为删除某个节点会同时删除该节点的所有子孙节点,而这些被删除的节点的个数为:(被删节点的右值-被删节点的左值+1)/2,而任何一个节点同时具有唯一的左值和唯一的右值,故删除作废节点后,其他相应节点的左、右值需要调整的幅度应为:减少(被删节点的右值-被删节点的左值+1)。

采用预排序遍历树算法实现无限分级树形结构的设计及应用

采用预排序遍历树算法实现无限分级树形结构的设计及应用

这里我用一个简单商品 目 录作 为我f 的示例数据 .以下是它的结 『 J .
构 模型 .
再 数一遍 ,注意移动你的 手指 ).这些数字标明了各个节点之 的关 , 系 ,” 砥装 ” 的号是3 ,它 是 ” 和4 服装” — 8 子孙节点 I .我 仃 ll的 川样 J 可 以看到 所有左值 大于2 和右值 小于7 的节点都是” 男式” — 的子孙节 27
P ̄ e l r ,t
旗袍
l 1
】 2

童 装
上 裹
l 4
1 5
1 7
1 6 3
般装
我们 用” 和” t L 唱” 来表示左 右字段 ( 出于“ f 和” g t S L l t r h” Q 中 e” i 在 有特 殊的 意义 );另外 ,J 入了 ” p ” 段 ,来表示 当前节点 的深 J u d t字 eh 度 ,这在实际应用 中的 许多地方 ,都能提供更方便的功能 我f 现在 『 J 可 以从数据 库中获取数据了 ,例如我们需要得到” 男式 ” 项下的所有节 点 就 可 以 这 样 写 查 瑚 语 句 : S L T F OM re WHE E I E EC R t e R f t
式 ”的左侧写上2 后继 续前进 ,沿着整 个树 的边缘给每 一个节点都 然
标 上左侧 和右侧的数字 ,最 后一个数字是 标在 “ 装”右 侧的 1 服 8 , 在 下面的这张图 中你可 以看到整个标好了数字的 多级结构 ( 没有看 懂 ? 你的手指指 着数字从 l 数到 l就明 白怎么四事 了 还 不明 白, 8
关键 词 预排序遍历 无限分美 树 形结构 随 着汁算机的发展 ,尤其是软件技术的广泛应用 ,产品分类 、多
级的 树状 结构 的沦坛 、 邮件 列表等 许多地方我 f 都 会遇 到这佯 的『 『 J u J 题 :如何存储 多级结构 的数据 ?如何 让多级结构的操作更高效 、 更准

树状数组维护区间最值模板

树状数组维护区间最值模板

树状数组维护区间最值模板1. 什么是树状数组?树状数组(Fenwick Tree),也称为二进制索引树(Binary Indexed Tree,BIT),是一种用于高效计算前缀和、区间和以及维护区间最值的数据结构。

它可以在O(logn)的时间复杂度内完成单点更新和查询操作。

2. 树状数组的原理树状数组的核心思想是利用二进制位的特性来进行高效计算。

它将原始序列分解为多个子序列,并利用每个子序列的前缀和来表示该子序列中元素的累加和。

具体地,设原始序列为a[1…n],树状数组C[1…n]用于存储每个子序列的前缀和。

其中,C[i]表示以a[i]为末尾元素的子序列的累加和。

对于某个位置i,其对应的父节点位置可以通过将i的二进制表示中最低位1变为0来计算得到。

例如,对于二进制表示为1010(十进制为10)的位置i,其父节点位置为1000(十进制为8)。

树状数组支持两种操作:单点更新和区间查询。

•单点更新:当某个位置i发生变化时,需要更新其对应的所有父节点位置的值。

具体操作为将i的二进制表示中最低位1变为0,并依次向上更新。

•区间查询:要求计算区间[l, r]的和(或最值),可以通过计算C[r] - C[l-1]得到。

其中,C[r]表示以a[r]为末尾元素的子序列的累加和,C[l-1]表示以a[l-1]为末尾元素的子序列的累加和。

这样计算得到的差值即为区间[l, r]内元素的累加和。

3. 树状数组维护区间最值模板树状数组不仅可以用于维护前缀和,还可以用于维护区间最值。

以下是树状数组维护区间最值的模板代码:const int MAXN = 100000; // 树状数组大小int a[MAXN]; // 原始序列int C[MAXN]; // 树状数组// 单点更新操作void update(int pos, int val) {while (pos <= MAXN) {C[pos] = max(C[pos], val); // 维护区间最大值,如果是求和则改为C[pos]+= valpos += lowbit(pos); // 计算下一个父节点位置}}// 区间查询操作int query(int pos) {int res = 0;while (pos > 0) {res = max(res, C[pos]); // 维护区间最大值,如果是求和则改为res+=C[pos] pos -= lowbit(pos); // 计算下一个查询位置}return res;}// 计算pos的二进制表示中最低位1所对应的值int lowbit(int pos) {return pos & -pos;}4. 树状数组维护区间最值模板的使用示例以下是一个使用树状数组维护区间最值模板的示例,用于求解原始序列中某个区间内的最大值:#include <iostream>using namespace std;const int MAXN = 100000; // 树状数组大小int a[MAXN]; // 原始序列int C[MAXN]; // 树状数组// 单点更新操作void update(int pos, int val) {while (pos <= MAXN) {C[pos] = max(C[pos], val);pos += lowbit(pos);}}// 区间查询操作int query(int pos) {int res = 0;while (pos > 0) {res = max(res, C[pos]);pos -= lowbit(pos);}return res;}// 计算pos的二进制表示中最低位1所对应的值int lowbit(int pos) {return pos & -pos;}int main() {int n; // 序列长度cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];update(i, a[i]);}int q; // 查询次数cin >> q;while (q--) {int l, r; // 查询区间cin >> l >> r;int max_val = query(r) - query(l-1);cout << "区间最大值:" << max_val << endl;}return 0;}5. 总结树状数组是一种高效的数据结构,适用于解决多种问题,包括维护前缀和、区间和以及维护区间最值等。

mysql生成树形结构知识点

mysql生成树形结构知识点

mysql生成树形结构知识点
生成树形结构是指根据某个表中的数据,构建出一个树状的结构,其中每个节点都有一个或多个子节点。

在MySQL中,可以使用以下几种方法来生成树形结构:
1. 递归查询:使用递归查询可以直接从表中查询出树形结构。

一般使用WITH RECURSIVE语法来实现,可以不断地迭代查询,直到找到根节点为止。

2. 嵌套集模型(Nested Set Model):嵌套集模型是一种将树状结构表示为一系列的左右值的方法。

根据左右值可以方便地查询到某个节点的所有子节点,以及该节点的父节点。

3. 路径枚举模型(Path Enumeration Model):路径枚举模型是一种将树状结构表示为路径字符串的方法。

每个节点都有一个路径字符串,包含了从根节点到该节点的路径。

可以通过匹配路径字符串来查询子节点和父节点。

4. 存储过程:使用存储过程来逐层构建树形结构。

可以通过循环迭代查询,并逐层插入数据到结果表中,最终构建出树形结构。

以上是一些常见的方法,每种方法都有其适用的场景和使用方式。

选择合适的方法取决于具体的需求和数据结构。

数据结构——用C语言描述 第六章 树状结构

数据结构——用C语言描述  第六章 树状结构

数据结构——用C语言描述第六章树状结构在计算机科学中,数据结构是组织和存储数据的方式,以便能够高效地访问和操作这些数据。

树状结构是一种重要的数据结构,它在许多算法和应用中都发挥着关键作用。

树状结构就像是一棵倒立的树,有一个根节点,然后从根节点向下延伸出许多分支,每个分支又可以进一步延伸出更多的分支。

这种结构使得数据的组织和管理更加清晰和高效。

在树状结构中,每个节点可以包含数据以及指向其子节点的指针。

节点之间通过这些指针形成层次关系。

树状结构的一个重要特点是,除了根节点外,每个节点都有且仅有一个父节点。

二叉树是树状结构中最常见的一种形式。

二叉树中的每个节点最多有两个子节点,分别称为左子节点和右子节点。

二叉搜索树是一种特殊的二叉树,它具有一定的规则。

对于二叉搜索树中的每个节点,其左子树中的所有节点的值都小于该节点的值,而其右子树中的所有节点的值都大于该节点的值。

这种特性使得在二叉搜索树中进行查找、插入和删除操作的效率很高。

例如,如果要在二叉搜索树中查找一个值,我们可以从根节点开始。

如果要查找的值小于当前节点的值,就向左子树继续查找;如果大于当前节点的值,就向右子树继续查找。

直到找到目标值或者确定该值不存在。

用 C 语言来实现二叉搜索树,首先需要定义一个节点结构体,来存储节点的数据以及左右子节点的指针。

```ctypedef struct TreeNode {int data;struct TreeNode left;struct TreeNode right;} TreeNode;```接下来,实现插入节点的函数。

插入节点时,需要按照二叉搜索树的规则,找到合适的位置插入新节点。

```cvoid insertNode(TreeNode root, int value) {if (root == NULL) {root =(TreeNode )malloc(sizeof(TreeNode));(root)>data = value;(root)>left = NULL;(root)>right = NULL;return;}if (value <(root)>data) {insertNode(&((root)>left), value);} else if (value >(root)>data) {insertNode(&((root)>right), value);}}```查找节点的函数也类似,根据比较值的大小在左右子树中递归查找。

数据结构树的逻辑表示方法

数据结构树的逻辑表示方法

数据结构树的逻辑表示方法数据结构树是一种以分层的方式,将数据组织成树形结构的一种数据结构。

它由一个或多个节点组成,每个节点包含一个数据元素和若干指向其他节点的指针。

树的逻辑表示方法主要包括,孩子兄弟表示法、双亲表示法和邻接表表示法。

孩子兄弟表示法是一种常用的表示树的方法。

它通过将每个节点分别表示为一个数据元素和两个指针,分别指向该节点的第一个孩子和该节点的下一个兄弟节点。

这样,可以有效地表示一棵树,且插入和删除节点的操作也相对较为简单。

例如,假设有以下一棵树:A/ \B C/ \D E可以使用孩子兄弟表示法表示为:节点A:数据元素为A,指针1指向节点B,指针2指向节点C。

节点B:数据元素为B,指针1指向节点D,指针2指向节点E。

节点C:数据元素为C,指针1为空,指针2为空。

节点D:数据元素为D,指针1为空,指针2为空。

节点E:数据元素为E,指针1为空,指针2为空。

这样,通过孩子兄弟表示法,我们可以方便地表示并操作这棵树。

双亲表示法是另一种常见的表示树的方法。

它通过定义一个数组,数组的下标表示节点的编号,数组的值表示节点的父节点的编号。

通过这种方式,可以快速地找到一个节点的父节点。

例如,假设有以下一棵树:A(0)/ \B(1) C(2)/ \D(3) E(4)可以使用双亲表示法表示为一个数组:[0, 0, 1, 1, 2]数组的下标表示节点的编号,数组的值表示节点的父节点的编号。

例如,第一个值0表示节点A的父节点是根节点,第二个值0表示节点B的父节点是根节点,以此类推。

通过双亲表示法,可以快速地找到一个节点的父节点,但是找到一个节点的子节点和兄弟节点则相对较为困难。

邻接表表示法是另一种常用的表示树的方法。

它通过使用链表来表示树中的每个节点,并使用一个数组来存储每个节点的指针。

数组的下标表示节点的编号,数组的值表示节点的指针所指向的链表。

例如,假设有以下一棵树:A(0)/ \B(1) C(2)/ \D(3) E(4)可以使用邻接表表示法表示为一个数组和链表:数组:[A, B, C, D, E]链表:[B -> D -> E, C, NULL, NULL, NULL]数组存储着每个节点的指针,链表存储着每个节点的子节点。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

采用左右值编码来存储无限分级树形结构的数据库表设计之前我介绍过一种按位数编码保存树形结构数据的表设计方法,详情见:浅谈数据库设计技巧(上)该设计方案的优点是:只用一条查询语句即可得到某个根节点及其所有子孙节点的先序遍历。

由于消除了递归,在数据记录量较大时,可以大大提高列表效率。

但是,这种编码方案由于层信息位数的限制,限制了每层能所允许的最大子节点数量及最大层数。

同时,在添加新节点的时候必须先计算新节点的位置是否超过最大限制。

上面的设计方案必须预先设定类别树的最大层数以及最大子节点数,不是无限分级,在某些场合并不能采用,那么还有更完美的解决方案吗?通过google的搜索,我又探索到一种全新的无递归查询,无限分级的编码方案——左右值。

原文的程序代码是用php写的,但是通过仔细阅读其数据库表设计说明及相关的sql语句,我彻底弄懂了这种巧妙的设计思路,并在这种设计中新增了删除节点,同层平移的需求(原文只提供了列表及插入子节点的sql语句)。

下面我力图用比较简短的文字,少量图表,及相关核心sql语句来描述这种设计方案:首先,我们弄一棵树作为例子:商品|---食品| |---肉类| | |--猪肉| |---蔬菜类| |--白菜|---电器|--电视机|--电冰箱select count(*) from tree where lft <= 2 and rgt >= 11为了方便列表,我们可以为tree表建立一个视图,添加一个层数列,该类别的层数可以写一个自定义函数来计算。

该函数如下:CREATE FUNCTION dbo.CountLayer(@type_id int)RETURNS intASbegindeclare@result intset@result=0declare@lft intdeclare@rgt intif exists (select1from tree where type_id=@type_id)beginselect@lft=lft,@rgt=rgt from tree where type_id=@type_idselect@result=count(*) from tree where lft <=@lft and rgt >=@rgtendreturn@resultendGO然后,我们建立如下视图:CREATE VIEW dbo.TreeViewASSELECT type_id, name, lft, rgt, dbo.CountLayer(type_id) AS layer FROM dbo.tree ORDE R BY lftGO()AS declare declare ifgo假定我们要在节点“肉类”下添加一个子节点“牛肉”,该树将变成:1商品18+2+--------------------------------------------+2食品11+2 12+2电器17+2+-----------------+ +-------------------------+3肉类6+2 7+2蔬菜类10+2 13+2电视机14+2 15+2电冰箱16+2 +-------------+4猪肉5 6牛肉78+2白菜9+2看完上图相应节点左右值的变化后,相信大家都知道该如何写相应的sql脚本吧?下面我给出相对完整的插入子节点的存储过程:CREATE PROCEDURE[dbo].[AddSubNodeByNode](@type_id int,@name varchar(50))ASdeclare@rgt intif exists (select1from tree where type_id=@type_id)beginSET XACT_ABORT ONBEGIN TRANSACTIONselect@rgt=rgt from tree where type_id=@type_idupdate tree set rgt=rgt+2where rgt>=@rgtupdate tree set lft=lft+2where lft>=@rgtinsert into tree (name,lft,rgt) values (@name,@rgt,@rgt+1)COMMIT TRANSACTIONSET XACT_ABORT OFFend然后,我们删除节点“电视机”,再来看看该树会变成什么情况:1商品20-2+-----------------------------------+2食品13 14电器19-2+-----------------+3肉类8 9蔬菜类12 17-2电冰箱18-2+----------+4猪肉5 6牛肉7 10白菜11相应的存储过程如下:CREATE PROCEDURE[dbo].[DelNode]@type_id intASdeclare@lft intdeclare@rgt intif exists (select1from tree where type_id=@type_id)beginSET XACT_ABORT ONBEGIN TRANSACTIONselect@lft=lft,@rgt=rgt from tree where type_id=@type_iddelete from tree where lft>=@lft and rgt<=@rgtupdate tree set lft=lft-(@rgt-@lft+1) where lft>@lftupdate tree set rgt=rgt-(@rgt-@lft+1) where rgt>@rgtCOMMIT TRANSACTIONSET XACT_ABORT OFFEnd注意:因为删除某个节点会同时删除该节点的所有子孙节点,而这些被删除的节点的个数为:(被删节点的右值-被删节点的左值+1)/2,而任何一个节点同时具有唯一的左值和唯一的右值,故删除作废节点后,其他相应节点的左、右值需要调整的幅度应为:减少(被删节点的右值-被删节点的左值+1)。

最后,让我们看看平移节点“电器”,将其和其所有子孙节点移动到节点“食品”之前后,该树会变成什么情况:1商品18+-----------------------------------+14-12电器17-12 2+4食品13+4+----------------------+ 15-12电冰箱16-12 3+4肉类8+4 9+4蔬菜类12+4+-------------------+4+4猪肉5+4 6+4牛肉7+4 10+4白菜11+4大家仔细观察一下交换后同层2个节点和其所有子孙节点左右值的变化,可以发现一个明显的规律,那就是,节点“电器”及其所有子孙节点的左右值均减少12,而节点“食品”及其所有子孙节点的左右值均增加4。

而节点“电器”+其子孙节点的数量为2,节点“食品”+其子孙节点的数量为6,这其中有什么联系吗?还记得我在删除节点的存储过程后面的注释吗?任何一个节点同时具有唯一的左值和唯一的右值。

让我们把节点数量*2,正好和节点左右值需要调整的幅度相等。

由此规律,我们可以编写出类似下面的存储过程来实现节点同层前移的功能:CREATE PROCEDURE[dbo].[MoveNodeUp]@type_id intASdeclare@lft intdeclare@rgt intdeclare@layer intif exists (select1from tree where type_id=@type_id)beginSET XACT_ABORT ONBEGIN TRANSACTIONselect@lft=lft,@rgt=rgt,@layer=layer from TreeView where type_id=@type_idif exists (select*from TreeView where rgt=@lft-1and layer=@layer)begindeclare@brother_lft intdeclare@brother_rgt intselect@brother_lft=lft,@brother_rgt=rgt from TreeView where rgt=@lft-1an d layer=@layerupdate tree set lft=lft-(@brother_rgt-@brother_lft+1) where lft>=@lft and rgt <=@rgtupdate tree set lft=lft+(@rgt-@lft+1) where lft>=@brother_lft and rgt<=@br other_rgtupdate tree set rgt=rgt-(@brother_rgt-@brother_lft+1) where rgt>@brother_ rgt and rgt<=@rgtupdate tree set rgt=rgt+(@rgt-@lft+1) where lft>=@brother_lft+(@rgt-@lft+ 1) and rgt<=@brother_rgtendCOMMIT TRANSACTIONSET XACT_ABORT OFFend注意:节点的同层平移可以采用临时表来做中介,降低代码的复杂度。

不用临时表来处理也行,但是update语句顺序一定要考虑周详。

否则,一旦出现bug,对整个类别表的破坏是惊人的,强烈推荐在做上述工作前对类别表进行完整备份。

同层下移的存储过程和同层上移类似,有兴趣的朋友可以自己动手编写体味一下其中的细节,我就不在这里列出来了。

最后,我对上面这种左右值编码实现无限分级类别树的方案做一个总结:优点:在消除递归的前提下实现了无限分级,而且查询条件是基于整形数字比较的,效率很高。

可以进行先序列表,添加,修改,删除,同层平移等常规操作,基本满足需求。

缺点:由于这种左右值编码的方式和常见的阿拉伯数字直观排序不同,再加上节点在树中的层次,顺序不是直观显示出来,而必须通过简单的公式计算后得到,需要花费一定的时间对其数学模型进行深入理解。

而且,采用该方案编写相关存储过程,新增,删除,同层平移节点需要对整个树进行查询修改,由此导致的代码复杂度,耦合度较高,修改维护的风险较高。

发表于@ 2007年04月26日16:36:00|评论(4 )|编辑新一篇: 自定义MembershipProvider来利用 2.0 Login控件的登陆和修改密码模块 | 旧一篇: 分页存储过程的一点心得老板心里你有多重?确立职场位置,明确自身重要性Leo教你看清前途老板心里你有多重?确立职场位置,明确自身重要性Leo教你看清前途评论#hometohome 发表于2008-05-07 22:17:19 IP: 123.115.4.*请问该如何根据子节点的type_id找出父节点呢?比如:猪肉的父节点是肉类、食品、商品#hometohome 发表于2008-05-07 22:38:54 IP: 123.115.4.*declare @rgt intselect @rgt=rgt from tree where type_id=13select * from tree where rgt>=@rgt and lft<=@rgt order by lft我是楼上的。

相关文档
最新文档