8树与树林

面向21世纪课程教材 普通高等教育“十一五”国家级规划教材 北京市高等教育精品教材 教育部普通高等教育精品教材

算法与数据结构

第八讲:树与树林

1

张乃孝等编著

《算法与数据结构—C语言描述》

5 二叉树与树 • 5.5 树及其抽象数据类型 • 5.6 树的实现 • 5.7 树林

2

5.5 树及其抽象数据类型

• 树的几种不同表现形式

3

基本定义

• 树是 n(n≥0)个结点的有限集T, T非空时满足:

–有且仅有一个特殊的称为根(root)的结点r; –除根结点外,其余结点可分为m(m≥0)个互不相交的 非空有限集T1, T2 , …,Tm ,其中每个集合又是一棵 非空树,称为 r 的子树(subtree)。 –结点数为0的树称为空树; –一棵非空树也可以没有子树(m=0),即这棵树只包 含一个根结点; –如有子树,则子树非空。

4

• 关于子树

主要概念

• • • • • • • • 空树 父结点、子结点、路径、路径长度 结点的度数 树的度数 无序树、有序树 结点的次序 最左子结点、长子、次子 右兄弟

5

抽象数据类型

ADT Tree is operations Tree createEmptyTree (void) 创建一棵空树。 Tree consTree(Node p ,Tree t1, …Tree ti) 以P为根,t1 …ti 为子树 创建一棵树。 int isNull ( Tree t ) 判断树t是否为空树。

6

Node root ( Tree t ) 返回树t的根结点。若为空树,则返回一特殊值。 Node parent (Node p ) 返回结点p的父结点。当指定的结点为根时,它 没有父结点,返回一个特殊值。 Tree leftChild (Tree t ) 返回树t的长子树。当指定树没有子树时,返回 一特殊值。 Tree rightSibling (Tree t ) 返回树t的右兄弟树。当指定树没有右兄弟子树 时,返回一特殊值。 end ADT Tree

7

树的周游

• 深度优先周游: 先根次序 :A B D E I J F C G H 后根次序 :D I J E F B G H C A

 

能否确定树结构?如何确定? 广度优先周游 : A B C D E F G H I J

8

深度优先周游:先根次序

/*按先根次序周游树的递归算法*/

void preOrder( Tree t ) { Tree c; if (t==NULL) return; visit( root(t) ); c = leftChild ( t ); while (c!=NULL) { preOrder ( c ); c = rightSibling ( c ); } }

9

按先根次序周游树的非递归算法

void nPreOrder ( Tree t ) { Tree c = t; Stack s = createEmptyStack ( ); /* 栈元素的类型是Tree */ do { while ( c!=NULL ) { visit ( root(c) ); push ( s, c ); c = leftChild ( c ); } while ((c==NULL)&&(!isEmptyStack(s))) { c = rightSibling( top(s)); pop(s); } } while(c!=NULL); }

10

深度优先周游:后根次序

/*按后根次序周游树的递归算法*/ void postOrder( Tree t ) { Tree c; if (t==NULL) return; c = leftChild ( t ); while (c!=NULL) { postOrder ( c );c = rightSibling ( c ); } visit(root(t) ); }

11

广度优先周游

void levelOrder(Tree t) { Tree c; Queue q; /* 队列元素的类型为Tree */ q = createEmptyQueue(); c =t; if (c==NULL) return; enQ

ueue(q,c); while (!isEmptyQueue(q)) { c = frontQueue(q); deQueue(q); visit( root(c) ); c = leftChild( c ); while (c!=NULL){ enQueue(q,c); c = rightSibling( c ); } } }

12

5.6 树的实现

父指针表示法  子表表示法  长子-兄弟表示法

13

父指针表示法

• 树中除根以外的每个结点都有唯一的一个父 结点。 • 根据这一特性,可用一组连续的存储空间, 即用一个数组存储树中的各个结点。 • 数组中的一个元素为一个结构,其中包括结 点本身的信息以及本结点的父结点在数组中 的下标。 • 树的这种存储方法称为父指针表示法。

14

父指针表示法

结点的结构可定义为: struct ParTreeNode { DataType info; int }; 树的类型定义为: struct ParTree{ int int }; typedef struct ParTree * PParTree; / 树类型的指针类型 */

15

/* 结点中的元素 */ /* 结点的父结点位置 */

parent;

MAXNUM n;

/* 树中最大结点个数 */ /* 树中已有结点的个数 */ /* 存放树中结点的数组 */

struct ParTreeNode * nodelist;

父指针表示法的改进

问题: 1)求结点的子结点和兄弟就需要查询整个数组。 2)没有表示出结点之间的左右次序,无法求树中某个 指定结点的最左子结点和右兄弟结点等基本运算。

改进方法是按一种周游次序在数组中存放结点,其中较 常见的一种方法是依次存放树的先根序列。

16

17

父指针表示法的算法

/*在父指针表示的树中求右兄弟结点的位置*/ int rightSibling_partree(PParTree t, int p) { int i; if (p>=0 && pn) for (i=p+1;in;i++) if (t->nodelist[i].parent==t->nodelist[p].parent) return i ; return -1; } /*在父指针表示的树中求最左子结点的位置*/ int leftChild_partree(PParTree t, int p) { if (t->nodelist[p+1].parent==p) return(p+1); else return -1 ; }

18

讨论

• 父指针表示方法的主要优点是存储空间 比较节省,对求某个结点的父母和求某 个结点的最左子结点操作都很方便,但 是对求某个结点的右兄弟运算比较慢 。

19

子表表示法

• 在把整棵树表示成一个结点表。 • 结点表中的每个元素又包含一个表,它记录了这个结 点的所有子结点的位置,称为子表(或者称为边表)。 • 结点表的长度即树中结点的个数,一般用一维数组顺 序存储;结点表中除了要保存元素本身的信息外,还 要保存子表的表头指针。 • 而子表的长度依赖于各结点的度数,所以各不相同, 一般用单链表表示;子表中结点的链接顺序是按其在 树中从左到右的次序进行的。

20

前面所示的树的子表表示

21

结点结构定义

struct EdgeNode { /* 子表中结点的结构 */ int }; struct ChiTreeNode { /* 结点表中结点的结构 */ DataType };

22

nodeposition; /* 子结点在结点表中的位置 */

struct EdgeNode *link; /* 指向下一个子表中的结

点 */

info;

/* 结点本身的信息 */

struct EdgeNode *children; /* 本结点子表的头指针 */

树结构定义

struct ChiTree { int int int }; typedef struct ChiTree * PChiTree; MAXNUM root; n; /* 树结构 */ /* 树中最大结点个数 */ /* 根结点的下标 */ /* 实际结点个数 */ /*结点表 */

struct ChiTreeNode * nodelist;

23

在树的子表表示中实现操作

在这种表示方法中求某个结点的最左子结点运算 很容易实现。 找到结点的全部子结点也很容易。 但求某个结点的父结点和右兄弟实现起来比较费 事,因为要找某结点的父结点必须依次检查哪个 结点的子表中是否包含该结点,而要找某结点的 右兄弟时,则首先要找到其父结点,然后再从父 结点的子表中找寻它的右兄弟结点。

24

在树的子表表示上求父结点位置

int parent_chitree(PChiTree t, int p) { int i; struct EdgeNode *v; for (i=0;in;i++) { /* 逐个检查树的各个结点,是不是父结点 */ v=t->nodelist[i].children; /* 若检查的结点子表中有p,则返回值是该结点的位置 */ while (v!=NULL) if (v->nodeposition==p) return i ; else v=v->link; } return(-1); /* 无父结点,则返回值为-1 */ }

25

在树的子表表示上求 右兄弟结点位置

int rightSibling_chitree(PChiTree t, int p) { int i; struct EdgeNode *v; for (i=0;in;i++){ v = t->nodelist[i].children; while (v!=NULL) if (v->nodeposition==p) if (v->link==NULL)return(-1); else return(v->link->nodeposition); else v=v->link; } return(-1); }

26

长子-兄弟表示法

在这种存储结构中,类型定义如下: struct CSNode; /* 树中结点结构 */ typedef struct CSNode * PCSNode; /* 结点的指针类型 */ struct CSNode { DataType info; PCSNode lchild; PCSNode rsibling; }; typedef struct CSNode * CSTree; /* 树类型定义 */ /* 结点结构定义 */ /* 结点中的元素 */ /* 结点的最左子结点的指针 */ /* 结点的右兄弟的指针 */

27

例子

28

长子-兄弟表示法的实现

• 采用长子-兄弟表示法表示树时,除parent和consTree 之外,其余的基本运算实现起来都是比较简单的,甚 至可以用一个简单的表达式或赋值语句代替函数调用。 • 找结点的全部子结点也很容易:先由lchild字段找到 长子,再由子结点的rsibling字段逐个地找子结点的 右兄弟。 • 长子-兄弟表示法的缺点是寻找某个指定结点的父结 点比较麻烦,需要对树进行周游,周游时检查被访问 的结点的各个子结点的位置是不是指定结点。

29

5.7 树林

• 树林是由零个或多个不相交的树所组成的集合。 • 树林中所有树也是有序的,彼此称为兄弟。 • 与自然界的树林有所不同,这里的树林可以是一个空 集,也可以只由一棵树构成。 • 如果从一棵树中将根结点(连同根结点到各子结点的 边)删除,便得到一个树林。 • 前边所介绍

的关于树的概念及术语对于树林基本都适 用。

30

树林的周游

• 先根次序周游:

–首先访问树林中第一棵树的根结点; –然后先根次序周游第一棵树除去根结点剩下的所 有子树构成的树林; –最后先根次序周游除去第一棵树之后剩下的树林。

• 后根次序周游:

–首先后根次序周游第一棵树的根结点的所有子树 构成的树林; –然后访问树林中第一棵树的根结点; –最后后根次序周游除去第一棵树之后剩下的树林。

31

树林的存储表示

• 前面所有树的表示方法都可以推广到树 林。下面给出用这些方法表示一个树林 的例子。

32

树林的父指针表示

33

树林的子表表示

34

树林的长子-兄弟表示

35

树林与二叉树的转换

在树林(包括树)与二叉树之间有一个自 然的一一对应的关系。 任何树林都唯一地对应到一棵二叉树; 任何二叉树也都唯一地对应到一个树林。

36

37

树林转换为二叉树

• 首先在所有相邻的兄弟结点之间加一条 线; • 然后 对每个非终端结点,只保留它到其 最左子结点的连线,删去它与其它子结 点之间原有的连线; • 最后以根结点为轴心,将整棵树顺时针 旋转一定角度(如45度),使其层次分 明。

38

树林转换为二叉树

把树林F看作树的序列:F = T1,T2,…,Tn, 对构造应于F的二叉树B(F)的定义可以递归描述如下: 若n = 0,则B(F)为空; 若n>0,则B(F)的根是T1的根w1, B(F)的左子树是B(T11,T12,…,T1m), 其中T11,T12,…,T1m是T1的子树; B(F)的右子树是B(T2,…,Tn )。

39

二叉树转换为树林

(a) 二叉树 (b) 加连线 (c) 删与右子结点的连线 (d) 调整

40

二叉树转换为树林

(1)若某结点是其父母的左子结点,则 把该结点的右子结点,右子结点的右子 结点……,都与该结点的父母用(虚) 线连起来; (2)去掉原二叉树中所有父母到右子结 点的连线; 整理由(1)、(2)两步所得到的树或树林, 使之结构层次分明。

41

二叉树转换为树林

设B是一棵二叉树,r是B的根,L是r的左子树,R是r的 右子树,则构造对应于B的树林F(B) 可作如下严格的递 归描述: 若B为空二叉树,则F(B)是空的树林; 若B不为空二叉树, 则F(B)是一棵树T1加上树林F(R), 其中树T1的根为r,r的子树为F(L)。

42

本讲重点

• 树是一种常见的树形结构,它常用的存储表示有三种: 父指针表示法、子表表示法和长子-兄弟表示法。周 游是树上的重要操作,主要有深度优先和广度优先两 种方式,在深度优先中又分为先根次序周游和后根次 序周游。 • 由于树/树林与二叉树之间存在对应关系,所以常常 把树与树林转换为二叉树处理。这使得二叉树的讨论 和它的llink-

rlink表示更加重要。 • 二叉树和树的各种存储方式是本章学习的重点。这些 存储方式都应该包(隐)含所有的结点和结点之间关 系的信息,不同的表示原则上应该可以相互转换。

43


相关文章

  • 红树林景观空间结构分析方法
  • 第40卷 第2期2016年3月 /j.issn.1000-2006.2016.02.017 JournalofNanjingForestryUniversity(NaturalSciencesEdition) 南京林业大学学报(自然科学版) ...

  • 广东海洋大学[海洋与环境]论文
  • 红树林生态系统对海洋环境影响的研究进展 学院: 班别: 学号: 摘要:红树林有海洋森林之称,主要生长在沿海地区.红树林生态系统对海洋有着非常大的影响,它不仅可以保护海洋环境,还可以为人类提供丰厚的资源.但是,红树林生态系统很容易受到人类活动 ...

  • 走进北海走进美丽的红树林
  • 掠影 Sketch走进北海 走进美丽的红树林北海市城建档案馆 李琼严涨潮后的山口红树林保护区中学时候,生物老师一说到红树林,总是滔滔不绝,她 描述中的红树林总是大片大片的 生长在同一个地方,在地底深处 根连着根,过着永不分离的日 子.我当时 ...

  • [红树林]教学设计
  • <红树林>教学设计 教材分析 <红树林>写了作者在海南岛琼山看到的海底森林红树林如仙境般美丽迷人的景象,不禁陶醉在这幽静而又神奇的仙境中.文章语言优美.生动,堪称写景佳作.文章从几个方面层层深入的介绍了海上奇观--红 ...

  • _珠海红树林_教学设计
  • 第22卷第9期中学生物学Vol.22No.92006 2006年MiddleSchoolBiology 文件编号:1003-7586(2006)09-0035-03 "珠海红树林"教学设计 赖翠敏 (广东省珠海市实验中学 ...

  • 东寨港红树林导游词
  • 各位朋友们,大家好。现在我们来到海口市演丰镇的东寨港红树林自然保护区。有朋友会问,这红树林为什么不是红色的,而是绿色的呢? 因为,这些生长在热带、亚热带海岸潮间带的常绿灌木或乔木群落,之所以称为红树林,只是因为在植物学上它们属于红树科,树皮 ...

  • 18[我爱在树林中漫步]教学设计
  • 18<我爱在树林中漫步> 承启学校 执教者:邓木娟 一.教学目标: [知识目标] 1.认读"焕.氧.碳.囱.嚣"5个生字. 2.理解课文内容,了解"我"爱在树林中散步的原因. [能力目标] ...

  • [红树林]教学设计及教学反思
  • 教学目标 1.运用列提纲的方法梳理课文主要内容,整体感知课文. 2.抓住具体语句,感受红树林的神奇和奉献精神. 3.了解其它树林奇观. 教学流程 一.借题发挥,想象激趣 1.出示单元主题,回忆在这单元里领略了哪些奇观? 2.这节课我们去欣赏 ...

  • 深圳大鹏半岛七娘山红树林植被实地考察报告
  • 深圳大鹏半岛七娘山红树林植被实地考察报告 实习时间:2005.7.19 实习人员:古伟唐 李康铭 曲俊樵 麦桂冰 姚兰 实习地自然概况: 大鹏半岛位于深圳龙岗区东南部,约114°28′~114°37′e , 22°26′~22°34′n , ...

© 2024 范文参考网 | 联系我们 webmaster# 12000.net.cn