数据结构授课教案第6章.docx
- 文档编号:5907885
- 上传时间:2023-01-02
- 格式:DOCX
- 页数:28
- 大小:26.45KB
数据结构授课教案第6章.docx
《数据结构授课教案第6章.docx》由会员分享,可在线阅读,更多相关《数据结构授课教案第6章.docx(28页珍藏版)》请在冰豆网上搜索。
数据结构授课教案第6章
山东轻工业学院
教师授课教案
课程名称:
数据结构(计科)
课程代码:
0301306
学分:
4.5
课程类别:
必修
开课单位:
信息科学与技术学院
授课班级:
授课教师:
杨春花
山东轻工业学院教务处制
授课时间
年月日星期第节
年月日星期第节
年月日星期第节
授课内容概要
第六章树和二叉树
第一节树的定义和术语
树的定义和表示方法;结点、度、叶子和分支结点、孩子和双亲、兄弟、祖先、层次和深度、堂兄弟、有序树、无序树、森林等基本术语。
第二节二叉树
二叉树的定义和性质;满二叉树和完全二叉树的定义和特点;二叉树的存储结构分类、二叉链表存储结构定义和二叉树的基本操作。
第三节二叉树的遍历和线索二叉树
(先序、中序、后序)遍历二叉树的操作定义、递归算法,中序遍历的非递归算法,二叉树的层次遍历;线索二叉树的定义、存储表示和实现。
第四节树和森林
树的存储结构:
双亲表示法、孩子表示法、孩子兄弟表示法;森林与二叉树的转换;树的先根和后跟遍历和森林的先序和中序遍历。
第五节哈夫曼树及其应用
赫夫曼树的定义和构造方法,前缀编码和赫夫曼编码的定义和赫夫曼编码/解码算法。
目的要求
目的:
理解树和二叉树的定义和实现。
基本要求:
理解树的定义、表示方法和相关术语,理解树和森林的遍历,理解哈夫曼树和哈夫曼编码的概念;掌握二叉树的定义、性质、存储结构和基本操作,掌握满二叉树和完全二叉树的概念和性质、二叉树遍历的定义、遍历的递归算法和中序遍历的非递归算法,掌握线索二叉树的概念和线索化的方法、树与二叉树的转换方法和哈夫曼树的构造方法。
重
点
二叉树的性质、存储结构;二叉树的遍历;二叉树的线索化;哈夫曼树的构造、哈夫曼编/译码。
难
点
二叉树的性质;二叉树遍历的算法;哈夫曼树的构造和哈夫曼编/译码。
作业布置
习题6
参考书
1.数据结构题集(C语言版),严蔚敏,清华大学出版社,2002。
3.数据结构、算法与应用-C++语言描述,(美)SartajSahni著,汪诗林等译,机械工业出版社,2002。
课型
理论课
学
时
分
配
复习
分钟
主要教具
投影、黑板
讲授
分钟
教学方法
讲解、提问、示例
指导
分钟
教学手段
板书、课件
总结
分钟
备注
共12学时,其中2学时为习题课
注:
课型一栏填写理论课、实验课、习题课等
授课内容
备注
第六章树和二叉树
树是一种重要的非线性数据结构。
树的特点:
每个结点至多有一个前驱,可有多个后继。
树的应用:
在现实中的应用:
如族谱、各种社会组织机构等。
在计算机领域:
编译程序中的语法树、数据库系统中的索引等。
6.1树的定义和基本术语
1、树的定义
树是由n(n≥0)个结点组成的有限集合。
如果n=0,称为空树;
否则,在一棵非空树中,满足如下两个条件:
(1)有一个特定的称之为根(root)的结点,它只有直接后继,但没有直接前驱;
(2)除根以外的其它结点划分为m(m≥0)个互不相交的有限集合T0,T1,…,Tm-1,每个集合又是一棵树,并且称之为根的子树(subTree)。
2、树的表示
(1)树型表示(直观表示法)
(2)二元组表示
(3)凹入法
(4)嵌套集合表示
(5)广义表表示(嵌套括号表示)
3、基本术语
结点(node):
包含一个数据元素及若干指向其它结点的分支信息。
结点的度(degree):
结点的子树个数
叶结点(leaf):
度为0的结点,也称为终端结点。
分支结点(branch):
度不为0的结点,也称为非终端结点。
孩子结点(child):
一个结点的直接后继或某结点子树的根结点。
双亲结点(parent):
一个结点的直接前驱或某个结点是其子树之根的双亲。
兄弟(sibling)结点:
具有同一双亲的所有结点
祖先(ancestor)结点:
若树中结点k到ks存在一条路径,则称k是ks的祖先
子孙(descendant)结点:
若树中结点k到ks存在一条路径,则称ks是k的子孙
结点所处层次(level):
根结点的层数为1,其余结点的层,其余结点的层数为双亲结点的层数加1
树的高度(depth):
树中结点的最大层数
树的度(degree):
树中结点的最大度数
有序树子树的次序不能互换
无序树子树的次序可以互换
森林(Forest)互不相交的树的集合
4、树的基本操作
1初始化
2求指定结点所在树的根结点
3求指定结点的双亲结点
4求指定结点的某一孩子结点
5求指定结点的最右边兄弟结点
6将一棵树插入到另一树的指定结点下作为它的子树
7删除指定结点的某一子树
8树的遍历
6.2二叉树(BinaryTree)
6.2.1二叉树的定义
1、二叉树(BinaryTree)或为空树,或由根及两棵不相交的左子树、右子树构成,并且左、右子树本身也是二叉树。
说明
1)二叉树中每个结点最多有两棵子树;二叉树每个结点度小于等于2;
2)左、右子树不能颠倒——有序树;
3)二叉树是递归结构,在二叉树的定义中又用到了二叉树的概念;
2、二叉树的五种不同形态
3、二叉树和树的区别:
二叉树不是树的特殊情形,它们是两个概念。
树和二叉树之间最主要的差别是:
二叉树中结点的子树要区分为左子树和右子树,即使在结点只有一棵子树的情况下也要明确指出该子树是左子树还是右子树。
6.2.2二叉树的性质
✓性质1:
在二叉树的第i层上至多有2i-1个结点(i≥1)
✓性质2:
深度为k的二叉树最多有2k-1个结点。
(k≥1)
✓性质3:
对任何一棵二叉树,如果其叶结点个数为n0,度为2的非叶结点个数为n2,则有n0=n2+1。
✓两种特殊的二叉树:
满二叉树:
深度为k且有2k-1个结点的二叉树。
在满二叉树中,每层结点都是满的,即每层结点都具有最大结点数。
完全二叉树:
若设二叉树的高度为h,除第h层外,其它各层的结点数都达到最大个数,第h层的结点集中出现在左端若干连续位置上,这就是完全二叉树。
完全二叉树举例.
✓性质4:
具有n个结点的完全二叉树的深度为
└log2n┘+1
证明:
设完全二叉树的高度为深度为h,则有2h-1-1 ✓性质5: 对于具有n个结点的完全二叉树,如果按照从上到下和从左到右的顺序对二叉树中的所有结点从1开始顺序编号,则对于任意的序号为i的结点有: (1)如i=1,则序号为i的结点是根结点,无双亲结点;如i>1,则序号为i的结点的双亲结点序号为└i/2┘。 (2)如2×i>n,则序号为i的结点无左孩子;如2×i≤n,则序号为i的结点的左孩子结点的序号为2×i。 (3)如2×i+1>n,则序号为i的结点无右孩子;如2×i+1≤n,则序号为i的结点的右孩子结点的序号为2×i+1。 6.2.3二叉树的存储结构 1、顺序存储结构 #defineMAXNODE100 typedefelemtypeSqBiTree[MAXNODE] SqBiTreebt; 顺序存储结构仅适用于完全二叉树 2、链式存储结构 (1)二叉链表: 二叉链表中每个结点包含三个域: 数据域、左指针域、右指针域 typedefstructnode{ ElemTypedata; structnode*lchild; structnode*rchild; }BiTNode,*BiTree; (2)三叉链表: 三叉链表中每个结点包含四个域: 数据域、双亲指针域、左指针域、右指针域 6.2.4二叉树的基本操作 创建二叉树 二叉树的遍历 6.3遍历二叉树和线索二叉树 6.3.1遍历二叉树(traversingbinarytree) 一、遍历二叉树的定义: 1、先序遍历(DLR) 若二叉树为空,则空操作;否则: (1)访问根结点; (2)先序遍历左子树; (3)先序遍历右子树; 2、中序遍历(LDR) 若二叉树为空,则空操作;否则: (1)中序遍历左子树; (2)访问根结点; (3)中序遍历右子树; 3、后序遍历(LRD) 若二叉树为空,则空操作;否则: (1)后序遍历左子树; (2)后序遍历右子树; (3)访问根结点; 例: 先序遍历、中序遍历、后序遍历下图所示的表达式语法树 二、遍历二叉树的递归算法 数据结构定义: typedefintElemType; typedefstructnode{ ElemTypedata; structnode*lchild,*rchild; }BiTNode,*BiTree; 1、先序遍历 PreOrderTranverse(BiTreeT) { if(T){ printf(“%d”,T->data);//访问的方式有多种 PreOrderTranverse(T->LChild); PreOrderTranverse(T->RChild); } } 2、中序遍历 InOrderTranverse(BiTreeT) { if(T){ InOrderTranverse(T->LChild); printf(“%d”,T->data);//访问的方式有多种 InOrderTranverse(T->RChild); } } 3、后序遍历 PostOrderTranverse(BiTreeT) { if(T){ PostOrderTranverse(T->LChild); PostOrderTranverse(T->RChild); printf(“%d”,T->data);//访问的方式有多种 } } 三、遍历二叉树的非递归算法 遍历的递归执行过程: (一)基于栈的递归消除 1、中序遍历的非递归算法 void InOrder(BiTreeT){ InitStack(S);push(S,T); while(! StackEmpty(S)){ if(Getop(S,p)&&p! =NULL) //向左走到尽头 {push(S,p->lchild;} pop(S,p);//空指针退栈 if(! StackEmpty(S)){//访问结点,向右一步 pop(S,p);visit(p->data); p=p->rchild; } } } void InOrder(BiTreeT){ InitStack(S);p=T; while(p! =NULL||! StackEmpty(S)) {if(p! =NULL) /*根指针进栈,遍历左子树*/ {push(S,p);p=p->lchild;} else { /*根指针退栈,访问根结点,遍历右子树*/ pop(S,p);visit(p->data); p=p->rchild; } } } 2、先序遍历的非递归算法 void PreOrder(BiTreeT){ InitStack(S);p=T; while(p! =NULL||! StackEmpty(S)) {if(p! =NULL) /*根指针进栈,遍历左子树*/ {visit(p->data);push(S,p);p=p->lchild;} else { /*根指针退栈,访问根结点,遍历右子树*/ pop(S,p); p=p->RChild; } } } 3、后序遍历的非递归算法 typedefstruct{ BiTreelink; intflag; }stacktype; void PostOrder(BiTreeT){ stacktypestack[MAXNODE];BiTreep;inttop,sign; if(T==NULL)return; top=-1;/*栈顶位置初始化*/ p=T; while(! (p==NULL&&top==-1)) {if(p! =NULL)/*结点第一次进栈*/ {top++; stack[top].link=p; stack[top].flag=1; p=p->lchild; } else{p=stack[top].link; sign=stack[top].flag; top--; if(sign==1)//结点第二次进栈 {top++; stack[top].link=p; stack[top].flag=2;//标记第二次出栈*/ p=p->rchild; } else{visit(p->data);p=NULL; } } } } 四、层次遍历二叉树 二叉树的层次遍历,是指从二叉树的第一层(根结点)开始,从上至下逐层遍历,在同一层中,则按从左到右的顺序对结点逐个访问。 例: voidLevelOrder(BiTreebt)/*层次遍历二叉树bt*/ {BiTreeQueue[MAXNODE];intfront,rear; if(bt==NULL)return; front=-1;rear=0;queue[rear]=bt; while(front! =rear) {front++;p=queue[front];Visit(p->data); if(p->lchild! =NULL)/*队首结点的左孩子入队*/ {rear++;queue[rear]=p->lchild;} if(p->rchild! =NULL)/*队首结点的右孩子入队*/ {rear++;queue[rear]=p->rchild;} } } 6.3.2遍历算法的应用 1.输出二叉树中的结点 输出二叉树中结点并无次序要求,因此可用任一种算法来完成。 voidPreOrder(BiTreeroot) /*先序遍历输出二叉树结点*/ {if(root! =NULL) {printf(root->data);/*输出根结点*/ PreOrder(root->LChild);/*先序遍历左子树*/ PreOrder(root->RChild);/*先序遍历右子树*/ } } 问题思考: 若要求统计二叉树中结点个数应如何去实现? 2.统计叶子结点数目 方法1: /*LeafCount保存叶子结点数目的全局变量,调用之前初始化值为0*/ voidleaf(BiTreeroot) {if(root! =NULL) {leaf(root->LChild); leaf(root->RChild); if(root->LChild==NULL&&root->RChild==NULL) LeafCount++; } } 方法2: intleaf(BiTreeroot) { if(root==NULL)return0; elseif((root->LChild==NULL)&&(root->RChild==NULL)) return1; else returnleaf(root->LChild)+leaf(root->RChild); } 3.建立二叉链表方式存储的二叉树 voidCreateBiTree(BiTree&bt) {ch=getchar(); if(ch=='.')bt=NULL; else{ bt=(BiTree)malloc(sizeof(BiTNode)); bt->data=ch; CreateBiTree(bt->LChild)); CreateBiTree(bt->RChild)); } } 4.在二叉树中查找具有给定值的结点 BiTreefindnode(BiTreet,ElemTypex) { if(t==NULL) return(NULL); elseif(t->data==x) return(t); else return(findnode(t->lchild)||findnode(t->rchild)); } 5.表达式运算 可以用二叉树表示表达式 前缀表达式、中缀表达式、后缀表达式分别是表达式树的前序、中序、后序遍历结果。 思考: 利用中缀表达式建立表达式树? 根据表达式树如何求得表达式的结果? 6.3.3线索二叉树 1.基本概念 二叉树的遍历是将二叉树中结点按一定规律线性化的过程。 当以二叉链表作为存储结构时,只能找到结点的左、右孩子信息,而不能直接得到结点在遍历序列中的前驱和后继信息。 要得到这些信息,第一种方法是将二叉树遍历一遍,在遍历过程中便可得到结点的前驱和后继,但这种动态访问浪费时间;第二种方法是充分利用二叉链表中的空链域,将遍历过程中结点的前驱、后继信息保存下来。 在有n个结点的二叉链表中共有2n个链域,有n+1个空链域。 我们可以利用剩下的n+1个空链域来存放遍历过程中结点的前驱和后继信息。 现作如下规定: 若结点有左子树,则其LChild域指向其左孩子,否则LChild域指向其前驱结点;若结点有右子树,则其RChild域指向其右孩子,否则RChild域指向其后继结点。 为了区分孩子结点和前驱、后继结点,为结点结构增设两个标志域: 二叉树的二叉线索存储表示: typedefenumPointerTag{Link,Thread}; typedefstructBitThrNode{ ElemTypedata; structBiThrNode*lchild,*rchild; PointerTagLTag,Rtag; }BiThrNode,*BiThrTree; 线索: 在这种存储结构中,指向前驱和后继结点的指针叫做线索。 线索链表: 以这种结构组成的二叉链表作为二叉树的存储结构,叫做线索链表。 线索化: 对二叉树以某种次序进行遍历并且加上线索的过程叫做线索化。 线索二叉树: 线索化了的二叉树称为线索二叉树。 2.二叉树的线索化 线索化实质上是将二叉链表中的空指针域填上相应结点的遍历前驱或后继结点的地址,而前驱和后继的地址只能在动态的遍历过程中才能得到。 因此线索化的过程是在遍历过程中修改空指针域的过程。 对二叉树按照不同的遍历次序进行线索化,可以得到不同的线索二叉树(先序线索二叉树、中序线索二叉树和后序线索二叉树)。 中序线索化算法: voidInOrderThreading(BiThrTree&Thrt,BiThrTreeT){ /*对二叉树T进行中序线索化,其中pre始终指向刚访问过的结点*/ if(! (Thrt=(BiThrTree)malloc(sizeof(BiThrNode)))return; Thrt->LTag=Link;Thrt->RTag=Thread; Thrt->rchild=Thrt; if(! T)Thrt->lchild=Thrt; else{Thrt->lchild=T;pre=Thrt; InThreading(T); pre->rchild=Thrt;pre->RTag=Thread; Thrt->rchild=pre;} } 中序线索化算法: voidInthreading(BiThrTreep){ if(p){ Inthread(root->LChild);/*线索化左子树*/ if(p->LChild==NULL) {p->Ltag=Thrad;p->LChild=pre;}/*置前驱线索*/ if(pre->RChild==NULL)/*置后继线索*/ {pre->RChild=p;pre=p;} Inthread(root->RChild);/*线索化右子树*/ } } 中序线索化二叉树的遍历算法: TRAVERSEINTHREAD(BiThrTreeT){ p=T->lchild; while(p! =T){ while(p->ltag==Link) p=p->lchild; visit(p->data); while(p->Rtag==Thread&&p->rchild! =T) {p=p->rchild;visit(p->data);} } } 3.在线索二叉树中找前驱、后继结点 voidInPre(BiTNode*p,BiTNode*pre) /*在中序线索二叉树中查找p的中序前驱,并用pre指针返回结果*/ {if(p->Ltag==1)pre=p->LChild;/*直接利用线索*/ else{/*在p的左子树中查找“最右下端”结点*/ for(q=p->LChild;q->Rtag==0;q=q->RChild); pre=q;} } voidInSucc(BiTNode*p,BiTNode*succ) /*在中序线索二叉树中查找p的后继结点,并用succ指针返回结果*/ {if(p->Rtag==1)succ=p->RChild;/*直接利用线索*/ else{/*在p的右子树中查找“最左下端”结点*/ for(q=p->RChild;q->Ltag==0;q=q->LChild); succ=q; } } 6.4树和森林 6.4.1树的存储结构 1、双亲表示法 找一个结点的双亲十分方便,但要找一个结点的孩子则要遍历整个结构 2、孩子链表表示法 找一个结点的孩子十分方便,但要找一个结点的双亲则要遍历整个结构 3、双亲孩子表示法 6.4.2森林和二叉树的转换 二叉树与树都可用二叉链表存贮,以二叉链表作中介,可导出树与二叉树之间的转换。 1.树转换为二叉树 ⑴树中所有相邻兄弟之间加一条连线。 ⑵对树中的每个结点,只保留其与第一个孩子结点之间的连线,删去其与其它孩子结点之间的连线。 ⑶以树的根结点为轴心,将整棵树顺时针旋转一定的角度,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 授课 教案
![提示](https://static.bdocx.com/images/bang_tan.gif)