4第四章 树和二叉树18学时.docx
- 文档编号:23897219
- 上传时间:2023-05-22
- 格式:DOCX
- 页数:57
- 大小:423.39KB
4第四章 树和二叉树18学时.docx
《4第四章 树和二叉树18学时.docx》由会员分享,可在线阅读,更多相关《4第四章 树和二叉树18学时.docx(57页珍藏版)》请在冰豆网上搜索。
4第四章树和二叉树18学时
课时教案
周次
第周第13次课
课题
§4.1树的逻辑结构和存储结构
授课
类型
理论课(√)、实践课()、实习()
时间设计
授
课
内
容
与
教
学
设
计
第四章树和二叉树
教学目的要求:
本章主要介绍树的基本概念,树的存储表示,树的遍历,树、森林和二叉树的转换,二叉树的定义、性质和存储结构,二叉树的遍历,哈夫曼树及其应用。
要求学生掌握树和二叉树的递归定义、有关的术语及基本概念;二叉树的性质及其表示方法,二叉树的存储结构;二叉树的三种遍历;树、森林和二叉树之间的相互转换;树、森林的遍历及存储结构;哈夫曼树的建立及其应用。
§4.1树的逻辑结构和存储结构
4.1.1树型结构实例
1.家族树
图4-1家族树
2.书的目录结构
图4-2书的目录
4.1.2树的定义
1.树的定义
树(Tree)是n(n≥0)个结点的有限集(记为T),T为空时称为空树,否则它满足以下两个条件:
(1)有且仅有一个结点没有前驱,称该结点为根结点(Root);
(2)除根结点以外,其余结点可分为m(m≥0)个互不相交的有限集合T0,Tl,…,Tm-1。
其中每个集合又构成一棵树,树T0,Tl,…,Tm-1被称为根结点的子树(Subtree)。
每棵子树的根结点有且仅有一个直接前驱,但可以有0个或多个后继。
树的逻辑结构表示数据之间的关系是一对多,或者多对一的关系。
它的结构特点具有明显的层次关系,是一种十分重要的非线性的数据结构。
图4-3树的示例
图4-3(a)是一棵只有一个根结点的树;图4-3(b)是一棵有12个结点的树,即T={A,B,C,…,K,L}。
A是树根,除根结点A之外,其余的11个结点分为三个互不相交的集合。
T1,T2和T3是根A的三棵子树,且本身又都是一棵树。
所以树的定义是递归的。
2.树的基本术语
树的结点包含一个数据元素及若干指向其子树的分支。
(1)结点的度:
一个结点拥有的子树个数,度为零的结点称为叶结点;
(2)树的度:
树中所有结点的度的最大值Max(D(I))
含义:
树中最大分支数为树的度;
(3)结点的层次及树的深度:
根为第一层,根的孩子为第二层,若某结点为第k层,则其孩子为k+1层.
树中结点的最大层次称为树的深度或高度
(4)森林:
是m(m>=0)棵互不相交的树的集合
森林与树概念相近,相互很容易转换.
(5)有序树、无序树如果树中每棵子树从左向右的排列拥有一定的顺序,不得互换,则称为有序树,否则称为无序树。
在树结构中,结点之间的关系又可以用家族关系描述,定义如下:
(6)孩子、双亲:
结点子树的根称为这个结点的孩子,而这个结点又被称为孩子的双亲。
(7)子孙:
以某结点为根的子树中的所有结点都被称为是该结点的子孙。
(8)祖先:
从根结点到该结点路径上的所有结点。
(9)兄弟:
同一个双亲的孩子之间互为兄弟。
(10)堂兄弟:
双亲在同一层的结点互为堂兄弟。
3.树的基本运算
树的基本运算主要有:
(⒈)初始化操作INITIATE(T):
创建一棵空树。
(⒉)求根函数ROOT(T):
求树T的根;ROOT(X):
求结点x所在树的根。
(⒊)求双亲函数PARENT(T,x):
在树T中求x的双亲。
(⒋)求第i个孩子函数CHILD(T,x,i):
在树T中求结点x的第i个孩子。
(⒌)建树函数CRT-TREE(x,F):
建立以结点x为根,森林F为子树的树。
(6.)遍历树操作TRAVERSE(T):
按顺序访问树T中各个结点。
4.1.3树的表示
树的逻辑表示方法有多种,常见的有:
1.树形图表示法
2.嵌套集合表示法(文氏图表示法)
3.凹入表示法
4.广义表表示法
4.1.4树的存储结构
和线性表一样,树可以用顺序和链式两种存储结构。
树的顺序存储结构适合树中结点比较“满”的情况。
根据树的非线性结构特点,常用链式存储方式来表示树。
树常用的存储方法有:
双亲存储表示法、孩子链表表示法和孩子兄弟链表表示法。
1.双亲存储表示法
一般采用顺序存储结构实现。
用一组地址连续的存储单元来存放树的结点,每个结点有两个域:
data域-----存放结点的信息;
parent域-----存放该结点双亲结点的位置
特点:
求结点的双亲很容易,但求结点的孩子需要遍历整个向量。
存储结构描述为:
#defineMaxTreeSize100//定义数组空间的大小
typedefcharDataType;//定义数据类型
typedefstruct
{DataTypedata;//结点数据
intparent;//双亲指针,指示结点的双亲在数组中的位置
}PTreeNode;
typedefstruct
{PTreeNodenodes[MaxTreeSize];
intn;//结点总数
}PTree;
PTreeT;//T是双亲链表
2.孩子链表表示法
这是树的链式存储结构。
每个结点的孩子用单链表存储,称为孩子链表。
n个结点可以有n个孩子链表(叶结点的孩子链表为空表)。
n个孩子链表的头指针用一个向量表示。
特点:
与双亲相反,求孩子易,求双亲难。
图4-6树的孩子链表结构
存储结构描述为:
typedefstructCTNode
{intchild;//孩子链表结点
structCTNode*next;
}*ChildPtr;
typedefstruct//孩子链表头结点
{ElemTypedata;//结点的数据元素
ChildPtrfirstchild;//孩子链表头指针
}CTBox;
typedefstruct
{CTBoxnodes[MaxTreeSize];
intn,r,//数的结点数和根结点的位置
}CTree;
孩子链表表示法的类型说明
typedefstructCnode//DataType和MaxTreeSize由用户定义
{//孩子链表结点
intchild;//孩子结点在数组中对应的下标
structCNode*next;
}Cnode;
typedefstruct//孩子链表头结点
{
DataTypedata;//存放树中结点数据
CNode*firstchild;//孩子链表的头指针
}PTNode;
typedefstruct
{
PTNodenodes[MaxTreeSize];
intn,root;//树的结点数和根结点的位置
}Ctree;
CtreeT;//T的孩子链表表示
3.孩子兄弟链表表示法
孩子兄弟链表表示法也是树的一种链式存储结构。
用二叉链表作为树的存储结构,每个结点的左链域指向该结点的第一个孩子,右链域指向下一个兄弟结点。
由于结点中的两个指针指示的分别为“孩子”和“兄弟”,故称为“孩子-兄弟链表”。
这种结构也称为二叉链表。
图4-7树的孩子-兄弟存储结构
特点:
双亲只管长子
长子连接兄弟
树的孩子兄弟链表的存储结构描述为:
typedefstructCSNode
{ElemTypedata;
structCSNode*firstchild,*nextsibling;
}CSNode,*CSTree;
孩子兄弟存储结构的最大优点是可以方便地实现树和二叉树的相互转换和树的各种操作。
但是,孩子兄弟存储结构的缺点也是查找当前结点的双亲结点比较麻烦,需要从树根结点开始逐个结点比较查找。
4.1.5树和森林的遍历
1.树的遍历
所谓树的遍历,就是按照某种顺序依次访问树中各个结点,并使得每个结点只被访问一次。
也就是把非线性结构的树结点变成线性序列的一种方式。
树的遍历可以按深度优先遍历,也可以按照广度优先(按层次)遍历。
深度优先遍历通常有两种方式:
前序遍历和后序遍历。
(1)前序遍历的递归定义:
若树T非空,则:
访问根结点R;
按照从左到右的顺序依次前序遍历根结点R的各子树T1,T2,…,Tk。
(2)后序遍历的递归定义:
若树T非空,则:
按照从左到右的顺序依次后序遍历根T的各子树Tl,T2,…,Tk;
访问根结点R。
广度优先(按层)遍历
广度优先(按层次)遍历定义为:
先访问第一层结点(即树根结点),再从左至右访问第二层结点,依次按层访问……,直到树中结点全部被访问为止。
对图4-6(a)中的树进行按层次遍历得到树的广度优先遍历序列为:
ABCDEFG。
说明:
①前序遍历一棵树恰好等价于前序遍历该树所对应的二叉树。
(4.2节将介绍二叉树)
②后序遍历树恰好等价于中序遍历该树所对应的二叉树。
树的先序遍历算法描述如下:
voidPreorder(Btree*root)//先根遍历k叉树
{if(root!
=NULL)
{printf(“%c\n”,root->data);//访问根结点
for(i=0;i preorder(root->t[i]);//递归前序遍历每一个子结点 } } 2.森林的遍历 森林的深度优先遍历通常也有两种方式: 前序遍历和后序遍历。 (1)前序遍历森林 若森林非空,则: 访问森林中第一棵树的根结点; 前序遍历第一棵树中根结点的各子树所构成的森林 前序遍历去掉第一棵树外其它树构成的森林。 (2)后序遍历森林 若森林非空,则: 后序遍历森林中第一棵树中根结点的各子树所构成的森林; 访问第一棵树的根结点; 后序遍历去掉第一棵树外其它树构成的森林。 当用二叉链表作为树和森林的存储结构时,树和森林的前序遍历和后序遍历可用二叉树的前序遍历和中序遍历算法来实现。 图4-8森林和对应的二叉树 12学时 2学时 1学时 授课重点、难点 教学重点: 熟悉树型结构常用术语,掌握基本概念以及树的存储。 教学难点: 树和森林的遍历。 课堂讨论、思 考题、 作业 作业: P159-163一、1-8二、1-4四、3。 教 学 后 记 课时教案 周次 第周第14次课 课题 §4.2二叉树 授课 类型 理论课(√)、实践课()、实习() 时间设计 授 课 内 容 与 教 学 设 计 §4.2二叉树 4.2.1二叉树的定义与性质 二叉树(BinaryTree)是另一种重要的树型结构。 是度为2的有序树,它的特点是每个结点至多有两棵子树。 和树结构的定义类似,二叉树的定义也可以用递归形式给出。 1.二叉树的递归定义 二叉树(BinaryTree)是n(n≥0)个结点的有限集。 它或者是空集(n=0),或者同时满足以下两个条件: (1)有且仅有一个根结点; (2)其余的结点分成两棵互不相交的左子树和右子树。 二叉树与树有区别: 树至少应有一个结点,而二叉树可以为空;树的子树没有顺序,但如果二叉树的根结点只有一棵子树,必须明确区分它是左子树还是右子树,因为两者将构成不同形态的二叉树。 因此,二叉树不是树的特例。 它们是两种不同的数据结构。 二叉树有5种基本形态: (a)空二叉树(b)只有根结点的二叉树(c)右子树为空的二叉树(d)左子树为空的二叉树(e)左右子树均不为空的二叉树 图4-9二叉树的五种基本形态 两种特殊形态的二叉树: 满二叉树和完全二叉树。 (1)满二叉树(FullBinaryTree) 深度为k,且有2k-1个结点的二叉树。 特点: (1)每一层上结点数都达到最大 (2)度为1的结点n1=0,树叶都在最下一层上。 结点层序编号方法: 从根结点起从上到下逐层(层内从左到右)对二叉树的结点进行连续编号。 (2)完全二叉树(CompleteBinaryTree) 深度为k,结点数为n的二叉树,当且仅当每个结点的编号都与相同深度的满二叉树中从1到n的结点一一对应时,称为完全二叉树。 图4-11完全二叉树 完全二叉树的特点: (1)每个结点i的左子树的深度Lhi-其结点i的右子树的深度Rhi等于0或1,即叶结点只可能出现在层次最大或次最大的两层上。 (2)完全二叉树结点数n满足2k-1-1<n≤2k-1 (3)满二叉树一定是完全二叉树,反之不成立。 2.二叉树的性质 性质1在二叉树的第i层上至多有2i-1个结点(i≥1)。 性质2深度为k的二叉树至多有2k-1个结点(k≥1)。 (深度一定,二叉树的最大结点数也确定) 性质3二叉树中,终端结点数n0与度为2的结点数n2有如下关系: n0=n2+1 性质4结点数为n的完全二叉树,其深度为log2n+l 性质5在按层序编号的n个结点的完全二叉树中,任意一结点i(1≤i≤n)有: ⑴i=1时,结点i是树的根;否则,结点i的双亲为结点i/2(i>1)。 ⑵2i>n时,结点i无左孩子,为叶结点;否则,结点i的左孩子为结点2i。 ⑶2i+1>n时,结点i无右孩子;否则,结点i的右孩子为结点2i+1。 4.2.2二叉树的存储结构 同线性表一样,二叉树的存储结构也有顺序和链表两种结构。 1.顺序存储结构 用一组地址连续的存储单元,以层序顺序存放二叉树的数据元素,结点的相对位置蕴含着结点之间的关系。 bt[3]的双亲为3/2=1,即在bt[1]中;其左孩子在bt[2i]=bt[6]中; 其右孩子在bt[2i+1]=bt[7]中。 一般二叉树也按完全二叉树形式存储,无结点处用0表示。 图 这种存储结构适合于完全二叉树,既不浪费存储空间,又能很快确定结点的存放位置、结点的双亲和左右孩子的存放位置,但对一般二叉树,可能造成存储空间的大量浪费。 例如: 深度为k,且只有k个结点的右单枝树(每个非叶结点只有右孩子),需2k-1个单元,即有2k-1-k个单元被浪费。 链式存储结构(二叉链表) 设计不同的结点结构,可以构成不同的链式存储结构。 常用的有: 二叉链表 三叉链表 线索链表用空链域存放指向前驱或后继的线索 由于二叉树每个结点至多只有2个孩子,分别为左孩子和右孩子。 因此可以把每个结点分成三个域: 一个域存放结点本身的信息,另外两个是指针域,分别存放左、右孩子的地址。 每个结点的结构表示为: 其中左链域lchild为指向左孩子的指针,右链域rchild为指向右孩子的指针,数据域data表示结点的值。 若某结点没有左孩子或右孩子,其相应的链域为空指针。 对应的结构类型定义如下: typedefstructnode {ElemTypedata; structnode*lchild; structnode*rchild; }BTree,*tree; 其中,tree是指向根结点的指针。 说明: ●一个二叉链表由根指针root唯一确定。 若二叉树为空,则root=NULL;若结点的某个孩子不存在,则相应的指针为空。 ●具有n个结点的二叉链表中,共有2n个指针域。 其中只有n-1个用来指示结点的左、右孩子,其余的n+1个指针域为空。 3.带双亲指针的二叉链表 由于经常要在二叉树中寻找某结点的双亲时,可在每个结点上再加一个指向其双亲的指针parent,形成一个带双亲指针的二叉链表。 就是三叉链表。 性质6含有n个结点的二叉链表中,有n+1个空链域。 二叉树存储方法的选择,主要依赖于所要实施的各种运算的频度。 4.2.3二叉树的基本运算及实现 1.二叉树的基本运算 (1)Inittree(&T) 功能: 初始化操作(建立一棵空的二叉树)。 (2)Root(T) 功能: 求二叉树的根。 (3)Parent(T,x) 功能: 求二叉树T中值为x的结点的双亲。 (4)Lchild(T,x) 功能: 求结点的左孩子。 (5)Rchild(T,x) 功能: 求结点的右孩子。 (6)Traverse(T) 功能: 遍历或访问二叉树T。 (7)creatree(&T) 功能: 创建二叉树T 2.二叉树部分运算的算法描述 (1)创建二叉树creatree(&root,str) 功能: 创建二叉树T。 算法描述如下: voidcreatree(BTree**b,char*str) {BTree*stack[MAXSIZE],p=NULL; inttop=-1,k,j=0; charch; *b=NULL; ch=str[j]; while(ch! =’\0’) {switch(ch) {case’(’: top++;stack[top]=p;k=1,break;//为左结点 case’)’: top--;break; case’,’: k=2;break;//为右结点 default: p=(BTree*)malloc(sizeof(BTree)); p->data=ch;p->lchild=p->rchild=NULL; p->data=ch;p->lchild=p->rchild=NULL; if(*b==NULL)//为根结点 *b=p; else {switch(k) {case1: stack[top]->lchild=p;break; case2: stack[top]->rchild=p;break; } } } j++; ch=str[j]; } } (2)查找给定的结点find(root,x) (3)找左孩子结点lchild(p)或右孩子结点rchild(p) (4)输出二叉树disptree(root) 2学时 授课重点、难点 教学重点: 二叉树的性质,二叉树的顺序和链接存储。 教学难点: 完全二叉树。 课堂讨论、思 考题、 作业 思考题: 二叉树的顺序存储有何优势? 教 学 后 记 课时教案 周次 第周第15、16次课 课题 §4.3遍历二叉树和线索二叉树 授课 类型 理论课(√)、实践课()、实习() 时间设计 授 课 内 容 与 教 学 设 计 §4.3遍历二叉树和线索二叉树 6.3.1遍历二叉树 在二叉树的一些应用中,常常要求在树中查找具有某种特征的结点,或者对树中全部结点逐一进行某种处理。 这就引入了遍历二叉树的问题,即如何按某条搜索路径访问树中的每一个结点,使得每一个结点仅切仅被访问一次。 遍历二叉树: 指按一定的规律对二叉树的每个结点,访问且仅访问一次的处理过程。 遍历对线性结构是容易解决的。 而二叉树是非线性的,因而需要寻找一种规律,使二叉树上的结点能排列在一个线性队列上,从而便于遍历。 访问是一种抽象操作,是对结点的某种处理,例如可以是求结点的度、或层次、打印结点的信息,或做其他任何工作。 一次遍历后,使树中结点的非线性排列,按访问的先后顺序变为某种线性排列。 遍历的次序: 假如以L、D、R分别表示遍历左子树、遍历根结点和遍历右子树,遍历整个二叉树则有DLR、LDR、LRD、DRL、RDL、RLD六种遍历方案。 若规定先左后右,则只有前三种情况,分别规定为: DLR——先(根)序遍历, LDR——中(根)序遍历, LRD——后(根)序遍历。 1.遍历方案 LDR中序遍历;LRD后序遍历;DLR先序遍历 1)中序遍历二叉树 算法思想: 若二叉树非空,则: 1)中序遍历左子树;2)访问根结点;3)中序遍历右子树。 算法描述: voidInorder(BiTreebt)//bt为根结点指针 {if(bt)//根非空 {Inorder(bt->lchild); visit(bt->data); Inorder(bt->rchild); } } 2)后序遍历二叉树 算法思想: 若二叉树非空,则: 1)后序遍历左子树;2)后序遍历右子树;3)访问根结点 算法描述: voidPostorder(BiTreebt)//bt为根结点指针 {if(bt)//根非空 {Postorder(bt->lchild); Postorder(bt->rchild); visit(bt->data); } } 3)先序遍历二叉树 算法思想: 若二叉树非空,则: 1)访问根结点;2)先序遍历左子树;3)先序遍历右子树 算法描述: voidPreorder(BiTreebt)//bt为根结点指针 {if(bt)//根非空 {visit(bt->data); Preorder(bt->lchild); Preorder(bt->rchild); } } 例: 表达式a+b×(c-d)-e/f 遍历结果: 中序: a+b×c-d-e/f 后序: abcd-×+ef/- 先序: -+a×b-cd/ef 2.遍历算法 中序遍历非递归算法,s为存储二叉树结点指针栈: voidinorder(BiTreebt) {InitStack(s);Push(s,bt); while(! StackEmpty(s)) {while(GetTop(s)) {Push(s,GetTop(s)->lchild); p=POP(s); if(! StackEmpty(s)) {visit(GetTop(s)->data); p=Pop(s); Push(s,p->rchild); } } } } 操作过程: 根结点先进栈,左结点紧跟根后面进栈,右结点在根出栈后入栈;每个结点都要进一次和出一次栈,并且总是访问栈顶元素,因此,算法正确,时间复杂度为O(n)。 通过上述三种不同的遍历方式得到三种不同的线性序列,它们的共同的特点是有且仅有一个开始结点和一个终端结点,其余各结点都有且仅有一个前驱结点和一个后继结点。 从二叉树的遍历定义可知,三种遍历算法的不同之处仅在于访问根结点和遍历左右子树的先后关系。 如果在算法中隐去和递归无关的语句printf(),则三种遍历算法是完全相同的。 遍历二叉树的算法中的基本操作是访问结点,显然,不论按那种方式进行遍历,对含n个结点的二叉树,其时间复杂度均为O(n)。 所含辅助空间为遍历过程中占的最大容量,即树的深度。 最坏的情况下为n,则空间复杂度也为O(n)。 3.二叉链表的构造 (1)基本思想 利用遍历可以实现对结点的一些操作,如求结点的双亲,求结点的孩子等。 还可以在遍历过程中生成结点,建立二叉树的存储结构。 前面介绍过用栈建立二叉树,此处介绍一种基于先序遍历的二叉树构
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 4第四章 树和二叉树18学时 第四 二叉 18 学时