【Oracle】存储过程 遍历树 举例emp表的树状结构

61 篇文章 2 订阅
29 篇文章 2 订阅

 

树的遍历

 编辑

同义词 遍历树一般指树的遍历

树的遍历是树的一种重要的运算。所谓遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次。二叉树的3种最重要的遍历方式分别称为前序遍历中序遍历后序遍历。以这3种方式遍历一棵树时,若按访问结点的先后次序将结点排列起来,就可分别得到树中所有结点的前序列表,中序列表和后序列表。相应的结点次序分别称为结点的前序、中序和后序。

中文名

树的遍历

概    括

计算机的一种重要的运算

类    别

计算机语言

分    类

前序,中序、后序

目录

  1. 定义
  2. 方法

定义

编辑

树的这3种遍历方式可递归地定义如下:

如果T是一棵空树,那么对T进行前序遍历中序遍历后序遍历都是空操作,得到的列表为空表。

如果T是一棵单结点树,那么对T进行前序遍历、中序遍历和后序遍历都只访问这个结点。这个结点本身就是要得到的相应列表。

否则,设T如图6所示,它以n为树根,树根的子树从左到右依次为T1,T2,..,Tk,那么有:

对T进行前序遍历是先访问树根n,然后依次前序遍历T1,T2,..,Tk。

对T进行中序遍历是先中序遍历T1,然后访问树根n,接着依次对T2,T3,..,Tk进行中序遍历。

对T进行后序遍历是先依次对T1,T2,..,Tk进行后序遍历,最后访问树根n。

树图结构树图结构

前序遍历和中序遍历可形式地依次描述如下 :

三种遍历可以形式地描述如下,其中用到了树的ADT操作:

Procedure Preorder_Traversal(v:NodeType); {前序遍历算法}

begin

Visite(v); {访问节点v}

i:=Leftmost_Child(v);

while i<>∧ do

begin

Preorder_Traversal(i);{从左到右依次访问v的每一个儿子节点i}

i:=Right_Sibling(i);

end;

end;

Procedure Inorder_Traversal(v:NodeType); {中序遍历算法}

begin

if Leftmost_Child(v)=∧ {判断v是否是叶节点}

then Visite(v)

else

begin

Inorder_Traversal(Leftmost_Child(v)); {中序遍历v的左边第一个儿子节点}

Visite(v); {访问节点v}

i:=Right_Sibling(Leftmost_Child(v)); {i=v的左边第二个儿子}

while i<>∧ do

begin

Inorder_Traversal(i);

{从左边第二个开始到最右边一个为止依次访问v的每一个儿子节点i}

i:=Right_Sibling(i);

end;

end;

end;

Procedure Postorder_Traversal(v:NodeType); {后序遍历算法}

begin

i:=Leftmost_Child(v);

while i<>∧ do

begin

Preorder_Traversal(i);{从左到右依次访问v的每一个儿子节点i}

i:=Right_Sibling(i);

end;

Visite(v); {访问节点v}

end;

方法

编辑

为了将一棵树中所有结点按某种次序列表,只须对树根调用相应过程。例如对图7中的树进行前序遍历中序遍历后序遍历将分别得到前序列表:A B E F I J

C D G H;中序列表:E B I F J A C G D H;后序列表:E I J F B C G H D A。

下面介绍一种方法可以产生上述3种遍历方式的结点列表。设想我们从树根出发,依逆时针方向沿树的外缘绕行(例如围绕图7中的树绕行的路线如图8所示)。绕行途中可能多次经过同一结点。如果我们按第一次经过的时间次序将各个结点列表,就可以得到前序列表;如果按最后一次经过的时间次序列表,也就是在即将离开某一结点走向其父亲时将该结点列出,就得到后序列表。为了产生中序列表,要将叶结点与内部结点加以区别。叶结点在第一次经过时列出,而内部结点在第二次经过时列出。

在上述3种不同次序的列表方式中,各树叶之间的相对次序是相同的,它们都按树叶之间从左到右的次序排列。3种列表方式的差别仅在于内部结点之间以及内部结点与树叶之间的次序有所不同。

一棵树进行前序列表或后序列表有助于查询结点间的祖先子孙关系。假设结点v在后序列表中的序号(整数)为postorder(v),我们称这个整数为结点v的后序编号。例如在图7中,结点E,I和J的后序编号分别为1,2和3。

结点的后序编号具有这样的特点:设结点v的真子孙个数为desc(v),那么在以v为根的子树中的所有结点的后序编号恰好落在postorder(v)- desc(v)与postorder(v)之间。因此为了检验结点x是否为结点y的子孙,我们只要判断它们的后序编号是否满足:

postorder(y)-desc(y)≤postorder(x)≤postorder(y)

前序编号也具有类似的性质。

学术论文

内容来自 

 

 

查看全部 

https://baike.baidu.com/item/%E9%81%8D%E5%8E%86/9796023?fr=aladdin

https://baike.baidu.com/item/%E9%81%8D%E5%8E%86/9796023?fr=aladdin

 

 

 

 

 

使用存储过程求emp表的树状结构

求出每个员工的上级(经理)并输出

 

create or replace procedure p_emp(v_empno emp.empno%type,v_level binary_integer) is

  cursor c is

    select * from emp where mgr = v_empno;

  v_str varchar2(256) := '';

begin

  for i in 1..v_level loop

    v_str := v_str || '   ';

  end loop;

  for emp in c loop

    dbms_output.put_line(v_str || emp.ename);

    p_emp(emp.empno,v_level+1);--递归调用存储过程

  end loop;

end;

 

--求出没有经理的员工

declare

  v_emp emp%rowtype;

begin

  select * into v_emp from emp where mgr is null;

  dbms_output.put_line(v_emp.ename);

  p_emp(v_emp.empno, 1);

end;

 

--或者我们已经知道7839是没有上级的

 

begin

  p_emp(7839, 1);

end;

 

--输出

KING

   JONES

      SCOTT

         ADAMS

      FORD

         SMITH

   BLAKE

      ALLEN

      WARD

      MARTIN

      TURNER

      JAMES

   CLARK

      MILLER

 

https://www.cnblogs.com/hjwublog/p/5968097.html?utm_source=itdadao&utm_medium=referral

 

 

 

 

 

 

利用oracle存储过程生成树编码

需求

字段

描述

备注

ID

主键,32位UUID

 

TYPE_CODE

编码

如:1-01-003

PARENT_ID

父节点ID,32位UUID

 

SORT_NUM

排序编号

正整数

假设顶级节点的TYPE_CODE为字符1,写存储过程把表中所有的节点TYPE_CODE生成好;

二级节点前面补一个龄,三级补两个零,依次类推;

实现关键点

n 不知道系统有多少层级,需要递归调用

通过递归调用自身;

n 如何动态在TYPE_CODE前面填充‘0’;通过计算‘-’的个数来确定层级,从而确定前缀的个数

tree_level:= (length(p_code)-length(replace(p_code,'-',''))) + 1;

 

n 前面填充前缀‘0’字符

lpad(to_char(cnt),tree_level,'0')

 

存储过程代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

CREATEOR REPLACE PROCEDURE INI_TREE_CODE

 

(

 

  V_PARENT_ID IN VARCHAR2

 

)AS

 

  p_id  varchar2(32);

 

  p_code varchar2(256);

 

  

 

  sub_num   number(4,0);

 

  tree_level number(4,0);

 

  cnt       number(4,0) default 0;

 

  

 

  cursor treeCur(oid varchar2) is

 

  select id,TYPE_CODE from eval_index_type

 

  where parent_id = oid

 

  order by sort_num;

 

    

 

BEGIN

 

  sub_num := 0;

 

  

 

  select id,type_code into p_id,p_code

 

  from eval_index_type

 

  where id = V_PARENT_ID

 

  order by sort_num;

 

  

 

  for curRow in treeCur(p_id) loop

 

    cnt := cnt +1;

 

    tree_level :=(length(p_code)-length(replace(p_code,'-',''))) + 1;

 

    

 

    update eval_index_type set type_code =p_code || '-' || lpad(to_char(cnt) ,tree_level,'0')

 

    where id = curRow.id;

 

    

 

    select COUNT(*) into sub_num fromeval_index_type where parent_id = p_id;

 

  

 

    if sub_num > 0 then

 

      INI_TREE_CODE (curRow.id);

 

    end if;

 

  end loop;

 

ENDINI_TREE_CODE;

https://www.2cto.com/database/201412/358382.html

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值