带有层号的先根遍历树存储基于plsql的代码实现
来源:互联网 发布:淘宝代运营团队 编辑:程序博客网 时间:2024/06/05 23:30
本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!
摘要:本文介绍了带有层号的先根遍历树存储基于plsql的代码实现,本文中涉及的代码编写于2014年3月。另外,本文提供了测试表创建语句以及插入节点、获取直接子节点、获取自身及子孙节点、获取根到指定节点的路径、删除节点等方法的存储过程源码与测试样例。
1 存储方式介绍
带有层号的先根遍历树存储方式的主要思想是通过记录先根遍历中第一次访问节点时的次序号(以下称左值)与回溯时第二次访问的次序号(以下称右值)来维护树型结构的层次关系。由先根遍历的概念可知,子节点的左值必然大于父节点左值,而右值必然小于父节点的右值。再结合排序操作就可以很容易的在不递归的情况下对树型数据进行各种查询操作。另外,在记录左值、右值的基础上,该方式还维护了节点的层号,以降低查询直接(父)子节点的时间复杂度。
带有层号的先根遍历树存储结构如表1-1所示。
表1-1 带有层号的先根遍历树的存储结构
2 建表语句
带有层号的先根遍历树在Oracle下的建表语句如下。
CREATE TABLE TREE( NODENAME NVARCHAR2(50) NOT NULL, LEVELNUM NUMBER(8) NOT NULL, LEFTVALUE NUMBER(8) NOT NULL, RIGHTVALUE NUMBER(8) NOT NULL );COMMENT ON TABLE TREE IS '带有层号的先根遍历树';COMMENT ON COLUMN TREE.NODENAME IS '节点名';COMMENT ON COLUMN TREE.LEVELNUM IS '层号,从1开始';COMMENT ON COLUMN TREE.LEFTVALUE IS '先根遍历左值';COMMENT ON COLUMN TREE.RIGHTVALUE IS '先根遍历右值';ALTER TABLE TREE ADD CONSTRAINT PK_NODENAME PRIMARY KEY (NODENAME);
3 插入节点
3.1 实现
插入节点存储过程代码如下:
procedure InsertNode --插入节点 (parentName in nvarchar2, --父节点名,插入根时为空 nodeName in nvarchar2 --节点名 ) is parentRight TREE.RIGHTVALUE%type; --父节点右值 parentLevel TREE.LEVELNUM%type; --父节点层次 begin if parentName is null then insert into TREE values (nodeName, 1, 1, 2); else --获取父节点右值 select RIGHTVALUE, LEVELNUM into parentRight, parentLevel from TREE where NODENAME = parentName; update TREE set LEFTVALUE = LEFTVALUE + 2 where LEFTVALUE > parentRight - 1; update TREE set RIGHTVALUE = RIGHTVALUE + 2 where RIGHTVALUE > parentRight - 1; insert into TREE values (nodeName, parentLevel + 1, parentRight, parentRight + 1); end if; end InsertNode;
3.2 测试
比如,我们要创建如图3-1所示的树。
图3-1 测试用例树结构图
要创建上面的树,可以调用以下示例代码:
begin -- Call the procedure tree_package.InsertNode('', 'A'); tree_package.InsertNode('A', 'B'); tree_package.InsertNode('A', 'C'); tree_package.InsertNode('A', 'D'); tree_package.InsertNode('C', 'E'); tree_package.InsertNode('C', 'F'); tree_package.InsertNode('C', 'G'); end;
执行后测试代码后,表记录被更新为如表3-1所示的状态。
表3-1 插入节点后的表记录
4 获取直接子节点
4.1 实现
获取直接子节点存储过程代码如下:
procedure GetChildren --获得子节点 (parentName IN NVARCHAR2, --父节点名 children OUT RETCURSOR --子节点名 ) is parentLeft TREE.LEFTVALUE%type; --父节点左值 parentRight TREE.RIGHTVALUE%type; --父节点右值 parentLevel TREE.LEVELNUM%type; begin select LEFTVALUE, RIGHTVALUE, LEVELNUM into parentLeft, parentRight, parentLevel from TREE where NODENAME = parentName; open children for select NODENAME from TREE where LEFTVALUE between parentLeft and parentRight and LEVELNUM = parentLevel + 1 order by LEFTVALUE asc; end GetChildren;
4.2 测试
比如我们要获取节点A的直接子节点,调用GetChildren 后,得到的游标如表4-1所示。
表4-1 获取直接子节点返回结果游标
5 获取当前节点及子孙节点
5.1 实现
获取当前节点及子孙节点存储过程代码如下:
procedure GetDescendants --获取子孙节点 (parentName IN NVARCHAR2, --父节点名 descendants OUT RETCURSOR --子孙节点名 )is parentLeft TREE.LEFTVALUE%type; --父节点左值 parentRight TREE.RIGHTVALUE%type; --父节点右值 begin select LEFTVALUE, RIGHTVALUE into parentLeft, parentRight from TREE where NODENAME = parentName; open descendants for select NODENAME from TREE where LEFTVALUE between parentLeft and parentRight order by LEFTVALUE asc; end GetDescendants;
5.2 测试
比如我们要获取节点A及其子孙节点,调用GetDescendants后,得到的游标如表5-1所示。
表5-1 获取当前节点及其子孙节点返回结果游标
6 获取根到指定节点的路径
6.1 实现
获取根到指定节点的路径存储过程代码如下:
procedure GetNodePath --获得节点路径 (node IN NVARCHAR2, --节点名 nodePath OUT RETCURSOR --节点路径 ) is nodeLeft TREE.LEFTVALUE%type; --节点左值 nodeRight TREE.RIGHTVALUE%type; --节点右值 begin select LEFTVALUE, RIGHTVALUE into nodeLeft, nodeRight from TREE where NODENAME = node; open nodePath for select NODENAME from TREE where LEFTVALUE <= nodeLeft and RIGHTVALUE >= nodeRight order by LEFTVALUE asc; end GetNodePath;
6.2 测试
比如我们要获取根到节点G的路径,调用GetNodePath后,得到的游标如表6-1所示。
表6-1 根到指定节点返回结果游标
7 删除节点
7.1 实现
删除节点的存储过程代码如下:
procedure DeleteNode --删除节点及其子节点 (node IN NVARCHAR2 --节点名 ) is nodeLeft TREE.LEFTVALUE%type; --节点左值 nodeRight TREE.RIGHTVALUE%type; --节点右值 delNodeCount NUMBER; --删除的节点数 begin select LEFTVALUE, RIGHTVALUE into nodeLeft, nodeRight from TREE where NODENAME = node; delNodeCount := (nodeRight - nodeLeft+1)/2; delete from TREE where LEFTVALUE >= nodeLeft and RIGHTVALUE <= nodeRight; update TREE set LEFTVALUE = LEFTVALUE - delNodeCount * 2 where LEFTVALUE > nodeLeft; update TREE set RIGHTVALUE = RIGHTVALUE - delNodeCount * 2 where RIGHTVALUE > nodeRight; end DeleteNode;
7.2 测试
比如,我们要删除节点C,则C的子节点E、F、G将一并删除。删除后的表记录状态如表7-1所示。
表7-1 删除节点后的表记录
- 带有层号的先根遍历树存储基于plsql的代码实现
- 基于栈来实现二叉树的先根遍历
- 二叉树的构造与遍历—先根构造,一维数组存储按层构造,先根,中根,后根遍历输出
- 树--递归实现先、中、后遍历,层序遍历和树的深度
- 二叉树的层序遍历 先序遍历
- 二叉树的遍历(先、中、后、层序)C实现
- 树的先根遍历
- 二叉树的创建,先序、中序、后序遍历的递归实现以及层序遍历
- C++实现二叉树的递归遍历与非递归遍历(先序、中序、后序、层序)
- 代码实现 由二叉树的先序遍历和中序遍历推出后序遍历
- 二叉树的先序建立、遍历、镜像、节点数、深度的具体代码实现
- 二叉树遍历的非递归算法(先序、中序、后序)代码实现
- pat 1090,树的遍历,层序,先根遍历,利用缓存来优化,“以土地换和平”
- 二叉树的遍历代码(先序遍历,中序遍历,后序遍历)
- JAVA下实现二叉树的先序、中序、后序、层序遍历(递归和循环)
- C语言非递归实现二叉树的先序、中序、后序、层序遍历
- JAVA下实现二叉树的先序、中序、后序、层序遍历(递归和循环)
- 我强大的二叉树(先序、层序创建,先序、中序、后序、层序遍历)
- Python学习笔记之连接MySQLdb
- @property知多少
- 13扩展一个Greenplum System
- HDU5813 Elegant Construction
- Python--键值对配置文件处理
- 带有层号的先根遍历树存储基于plsql的代码实现
- 数组选择排序和冒泡排序
- Python编程_Lesson004_list数据类型
- 函数和包 PL/SQL
- NP问题证明
- HDU 2159 FATE(完全背包)
- EditText获取被点击的字符,并选中(解决越界,解决不能获取焦点)
- IIS部署.NET项目
- Python--CSV文件处理