数据结构——C语言描述第4章-树及二叉树.pptx
《数据结构——C语言描述第4章-树及二叉树.pptx》由会员分享,可在线阅读,更多相关《数据结构——C语言描述第4章-树及二叉树.pptx(136页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、数据结构C语言描述(慕课版)第4章树及二叉树编著:张同珍&学校:上海交通大学树及二叉树1.树的定义和术语3.二叉树的遍历和实现4.最优二叉树及其应用2.二叉树5.等价类问题6.树和森林树在一个元素集合中,如果每个元素都有唯一的前驱,但可以有多个后继,这样的结构就叫树结构。树是有限个(n0)元素组成的集合,在这个集合中,有一个结点称为根,如果有其他的结点,这些结点又被分为若干个互不相交的非空子集,每个子集又是一棵树,称为根的子树,每个子树都有自己的根,子树的根为根结点的孩子结点。在这个示例中,A是根,其余结点分成了3个互不相交的非空子集,3个子集是分别以B、C、D为根的子树。术语:父结点的父结点
2、称祖父结点,从根到树中某个结点的路径上经过的所有结点,包括根结点,都称为这个结点的祖先结点,相对的,这些结点称为祖先结点的子孙结点。一个结点的子树的根称为该结点的孩子结点或儿子结点,反之,相对于孩子结点,该结点称为父结点。同一个父结点的结点互为兄弟结点,同一个祖父但不同父亲的结点互称为堂兄弟结点。A为B、C、D的父结点;B、C、D为A的孩子结点;除了A自身,树中所有其余结点都称为A的子孙结点;G、I、H是D的子孙结点;对结点G来说,D是它的父结点,A是它的祖父结点,而A和D都是G的祖先结点;E、F互为兄弟结点;F和G互为堂兄弟结点。0102030405术语:树结构中每个结点拥有的孩子结点的个数
3、称为该结点的度,度为0的结点称叶子结点或终端结点,度不为0的结点称非叶子结点或中间结点或非终端结点。树的度是树中每个结点的度的最大值。A的度为3,G的度为1,树的度为3,A、G是中间结点,H是叶子结点。术语:根的层次数通常规定为1,其余结点的层次数是其父结点的层次数加1。树中结点实际上是具有一种层次关系。树中所有结点的层次数的最大值就是树的高度。A的层次数为1;F、I的层次数为3;H的层次数为4;树的高度为4。术语:如果其孩子结点都被规定了一定的顺序,如谁是第一个孩子、谁是第二个孩子等,这棵树就称有序树。如果这是一棵有序树,D有两个孩子,其中G就是D的第一个孩子、I是D的第二个孩子。术语:有限
4、棵互不相交的树(0)构成的集合称为森林(Forest)。森林在形式上和树有很大的关系:如果删除一棵树的根结点,就得到了该树的所有子树构成的森林。如果将构成森林的各棵树之上增加一个根结点,使得这些树的根结点都作为新增根结点的孩子结点,那么就得到了一棵树。树的ADT:数据及关系:有限(n0)个相同类型的元素组成的集合,其中一个元素称为根,如果还有其余元素,则这些元素被分为若干个互不相交的非空子集,每个子集又是一棵树,每个子树又有自己的根,子树的根是根的孩子结点。树的ADT:操作:Constructor:Getroot:前提:已知树中的某一结点p。结果:得到结点p的第一个儿子结点。FirstChil
5、d:前提:已知根结点的数据元素值。结果:创建一棵树。前提:已知一棵树。结果:得到树的根结点。前提:已知树中的某一结点p和它的一个儿子结点u。结果:得到结点p的挨着儿子结点u的下一个儿子结点v。NextChild:前提:已知某一关键字key。结果:检索具有关键字key的结点v。Retrieve:前提:已知某结点p及新结点的数据值value。结果:根据value值创建一个新结点q,并将其插入作为结点p的儿子结点。InsertChild:前提:已知某结点p及它的儿子结点的序号k。结果:删除结点p的第k个儿子结点。DeleteChild:结果:若树未创建,返回True,否则返回False。IsEmpt
6、y:物理结构:遇到的问题:顺序结构:元素易存,关系难存。链式结构:每个结点孩子个数不同,故结构不统一。树及二叉树1.树的定义和术语3.二叉树的遍历和实现4.最优二叉树及其应用2.二叉树5.等价类问题6.树和森林二叉树二叉树的定义二叉树的存储二叉树的操作及实现二叉树的性质二叉树二叉树是有限个(n0)结点的集合。它或者为空,或者有一个结点作为根结点,如果有其余结点,其余结点分成左右两个互不相交的子集作为根结点的左右子树,每个子树又都是一棵二叉树。01OPTION二叉树不是一棵特殊的树。树是生活中实际存在的结构类型,而二叉树更多地是作为一种工具。02OPTION二叉树中结点个数可以为0,允许一棵空二
7、叉树存在,树中结点个数不能为0,必须至少是1。03OPTION二叉树中左右孩子要明确指出是左还是右,即便只有一个孩子,也要指明它是左子还是右子。有序树中孩子只是进行了排序,没有左右之分。有2个结点的二叉树和树的示例:二叉树的各种形态:(a)(b)是二叉树(c)是树如果一个二叉树中的每一层结点数量都达到了最大值,则该二叉树称为满二叉树或丰满树。如果一个二叉树有k层,其中k-1层都是满的,第k层可能缺少一些结点,但缺少的结点是自右向左的,则这样的二叉树称为完全二叉树。满二叉树是完全二叉树,完全二叉树不一定是满二叉树。满二叉树中的叶子结点都分布在最后一层,完全二叉树的叶子可能分布在倒数两层上。二叉树
8、二叉树的定义二叉树的存储二叉树的操作及实现二叉树的性质二叉树的性质:性质2:一棵高度为k的二叉树,最多具有2k1个结点。性质3:对于一棵非空二叉树,如果叶子结点数为n0,度数为2的结点数为n2,则有:n0n21。性质4:具有n个结点的完全二叉树的高度k=log2n +1。性质1:一棵非空二叉树的第i层上最多有2i-1个结点(i1)。性质5:如果对一棵有n个结点的完全二叉树中的所有结点按层次自上而下、每一层自左而右依次对其编号。若设根结点的编号为1,则对编号为i的结点(1in),有:二叉树的性质:010302如果i1,则该结点是二叉树的根结点;如果i1,则其父亲结点的编号为。如果2in,则编号为
9、i的结点无左儿子;否则,其左儿子的编号为2i。如果2i+1n,则编号为i的结点无右儿子;否则,其右儿子的编号为2i+1。证明:性质3:又因二叉树中除了根结点,每个结点都可以视作是由其父结点的一条分支引出的,所以二叉树中共有n-1条分支,这些分支又是由度为1和度为2的结点发出的,所以有:n-11*n12*n2(2)在一棵二叉树中,设结点总数为n、度为0的结点有n0个、度为1的结点为n1个、度为2的结点为n2个。则有:nn0n1n2(1)对于一棵非空二叉树,如果叶子结点数为n0,度数为2的结点数为n2,则有:n0n21。结合(1)(2)得:n0n21(3)二叉树二叉树的定义二叉树的存储二叉树的操作
10、及实现二叉树的性质二叉树的存储用一组连续的空间即数组来存储二叉树中的结点。每个结点除了包括元素值,还包括表达二叉树父子关系的字段。顺序存储:如果是一棵完全二叉树,用顺序结构存储可以更加简单。完全二叉树可以省去left、right字段,从下标关系中直接反映父子关系。父下标为i,左子下标2i+1,右子下标2i+2。顺序存储方式的好处是数组访问简单,不利之处是它需要事先预估出数据的最大规模。二叉树的链式存储有两种形式,一种是标准形式,一种是广义标准形式。链式存储:标准形式:链式存储:二叉树的链式存储有两种形式,一种是标准形式,一种是广义标准形式。广义标准形式:LeftDataRightParent用
11、广义标准形式存储找父结点容易,但找父结点的频率不高,因此标准形式才是二叉树最常用的存储结构。二叉树二叉树的定义二叉树的存储二叉树的操作及实现二叉树的性质二叉树的操作-在内存中创建一棵二叉树;-属性类操作如判二叉树空、获取根结点、求以某结点为根的二叉树中的结点个数和高度;-二叉树的整体删除;-按前序、后序和中序遍历二叉树的操作;二叉树结点的插入、删除操作,因不知其具体意义和要求,放到后序有实际插入、删除意义的章节中讲解。二叉树的操作voidcreateTree(BTree*tree,Typeflag);/创建一棵二叉树intSize(Node*T);/以T为根的二叉树的结点个数。intHeigh
12、t(Node*T);/以T为根的二叉树的高度。intIsEmpty(BTree*tree)return(tree-root=NULL);/二叉树为空返回非0,否则为0structNode*GetRoot(BTree*tree)returntree-root;voidMakeEmpty(BTree*tree);DelTree(tree-root);tree-root=NULL;/使二叉树为空voidPrintPreOrder(Node*T);/按前序遍历打印以T为根的二叉树的结点的数据值二叉树的操作voidPrintInOrder(Node*T);/按中序遍历打印以T为根的二叉树的结点的数据值v
13、oidPrintPostOrder(Node*T);/按后序遍历打印以T为根的二叉树的结点的数据值voidLevelOrder(Node*T);/按层次遍历打印以T为根的二叉树的结点的数据值voidDelTree(BTree*tree);/删除以T为根的二叉树,并释放所有相关结点操作算法思路借助一个队列来管理结点,先将根结点的值读入,在内存中创建根结点并主动将根结点地址进队,从队列中逐个将结点出队、提醒用户输入出队结点左右孩子信息、为孩子创建结点空间,并将孩子结点链到父结点左右孩子字段,并将孩子结点地址进队,让它们在队中等候出队、进而再生它们自己的孩子。反复循环,直到队空。二叉树的建立:函数S
14、ize和Height。如Size操作,如果二叉树为空,返回0,否则就返回根的个数1加上根的左、右子树中的结点个数;如Height操作,如果二叉树为空,返回0,否则就返回根的高度1加上根的左、右子树高度中的最大值。求属性的两个操作:必须先删除它的左、右子树,才能删除这棵二叉树的根结点,如果先删除根结点,左右子树信息就会找不到了,而删除左右子树可以用递归来实现。删除一棵二叉树:部分操作实现typedefstructTypedata;structNode*left;structNode*right;Node;typedefstructstructNode*root;TypestopFlag;BTre
15、e;部分操作实现voidcreateTree(BTree*tree,Typeflag)/创建一棵二叉树Typee,el,er;Typex;Queueque;Node*p,*pl,*pr;initialize(&que,30);tree-stopFlag=flag;printf(Pleaseinputtheroot:);scanf(%c,&e);if(e=flag)tree-root=NULL;return;部分操作实现scanf(%c,&x);/去除输入中的回车符p=(Node*)malloc(sizeof(Node);p-data=e;p-left=NULL;p-right=NULL;tre
16、e-root=p;/根结点为该新创建结点enQueue(&que,p);部分操作实现while(!isEmpty(&que)p=front(&que);/获得队首元素并出队deQueue(&que);printf(Pleaseinputtheleftchildandtherightof%crespectly,using%casnochild:,p-data,flag);scanf(%c%c,&el,&er);scanf(%c,&x);/去除输入中的回车部分操作实现if(el!=flag)/该结点有左孩子pl=(Node*)malloc(sizeof(Node);pl-data=el;pl-le
17、ft=NULL;pl-right=NULL;p-left=pl;enQueue(&que,pl);部分操作实现if(er!=flag)/该结点有右孩子pr=(Node*)malloc(sizeof(Node);pr-data=er;pr-left=NULL;pr-right=NULL;p-right=pr;enQueue(&que,pr);部分操作实现intSize(Node*T)/得到以t为根二叉树结点个数。if(!T)return0;return1+Size(T-left)+Size(T-right);intHeight(Node*T)/得到以T为根二叉树的高度。intmaxl,maxr;
18、if(!T)return0;maxl=Height(T-left);maxr=Height(T-right);if(maxlmaxr)return1+maxl;elsereturn1+maxr;部分操作实现voidDelTree(BTree*tree)/删除以二叉树tree,并释放所有相关结点Queueque;Node*p;p=GetRoot(tree);if(!p)return;/二叉树为空initialize(&que,30);enQueue(&que,p);部分操作实现while(!isEmpty(&que)p=front(&que);deQueue(&que);if(p-left)en
19、Queue(&que,p-left);if(p-right)enQueue(&que,p-right);free(p);tree-root=NULL;树及二叉树1.树的定义和术语3.二叉树的遍历和实现4.最优二叉树及其应用2.二叉树5.等价类问题6.树和森林二叉树的遍历:遍历即对结构中每个数据元素进行访问且每个元素只访问一次。010203层次遍历:如果二叉树为空,遍历操作为空。否则,从第一层开始,从上至下,逐层访问每一层结点。当访问某一层时,从左到右逐个访问每一个结点。前序遍历:如果二叉树为空,遍历操作为空。否则,先访问根结点,然后前序遍历根的左子树,再前序遍历根的右子树。可简记为:“根左右”
20、。中序遍历:如果二叉树为空,遍历操作为空。否则,先中序遍历根的左子树,然后访问根结点,最后中序遍历根的右子树。可简记为:“左根右”。对于一个二叉树,可以按照以下几种策略进行遍历:04后序遍历:如果二叉树为空,遍历操作为空。否则,先后序遍历根的左子树,然后后序遍历根的右子树,最后访问根结点。可简记为:“左右根”。从前序、中序、后序遍历的定义可以看出,它是以根相对于左右子树的访问顺序来决定的:前序根在前、中序根在中、后序根在后。至于左右子树,总是按照先左后右,因为先右后左和先左后右的操作处理是类似的。二叉树的遍历:二叉树的遍历:层次遍历:B、L、C、S、F、D、G、I、H前序遍历:B、L、S、C、
21、F、D、G、I、H中序遍历:L、S、B、F、C、I、G、H、D后序遍历:S、L、F、I、H、G、D、C、B二叉树的遍历实现层次遍历中序遍历后序遍历前序遍历两个遍历序列确定二叉树二叉树的层次遍历:二叉树的层次遍历为从上到下逐层访问,每一层从左到右逐个访问每个结点。下图中二叉树的层次遍历序列为B、L、C、S、F、D:层次遍历算法如果二叉树为空,遍历操作为空,结束。否则,首先将根结点进队,然后反复循环进行以下操作:用一个队列管理二叉树中的结点,算法思想如下:0102队首结点出队、访问,如果该结点有左子,左子进队;如果该结点有右子,右子进队。继续判队空与否,如果不空则进入下一轮循环;如果空则遍历结束。
22、voidLevelOrder(Node*T)/按层次遍历顺序打印以T为根的二叉树的结点的数据值。Queueque;Node*p;if(!T)return;initialize(&que,30);enQueue(&que,T);while(!isEmpty(&que)p=front(&que);deQueue(&que);printf(%c,p-data);if(p-left)enQueue(&que,p-left);if(p-right)enQueue(&que,p-right);二叉树的遍历实现层次遍历中序遍历后序遍历前序遍历两个遍历序列确定二叉树二叉树的前序遍历如果二叉树为空,遍历操作为空
23、。否则,先访问根结点,然后前序遍历根的左子树,再前序遍历根的右子树。可简记为:“根左右”。右图的前序遍历序列:B、L、S、C、F、D前序遍历的递归算法voidPrintPreOrder(Node*T)/按前序遍历顺序打印以T为根的二叉树的结点的数据值。if(!T)return;printf(%c,T-data);PrintPreOrder(T-left);PrintPreOrder(T-right);前序遍历的非递归算法用一个栈辅助前序遍历的非递归算法实现:如果二叉树为空,遍历结束。将根结点压栈。如果栈不空,重复以下操作,直到栈空。弹栈得到栈顶元素并访问它的值。如果该出栈元素右子不为空,右子进
24、栈。如果该出栈元素左子不为空,左子进栈。前序遍历的非递归算法前序遍历的非递归算法实现voidPrintPreOrder(Node*T)/按前序遍历顺序打印以T为根的二叉树的结点的数据值。stacks;Node*p;if(!T)return;Initialize(&s);push(&s,T);while(!isempty(&s)p=top(&s);pop(&s);printf(%c,p-data);if(p-right)push(&s,p-right);if(p-left)push(&s,p-left);非递归算法的时间复杂度分析:时间由程序中的循环决定,每次循环访问一个结点,共n个结点,需要循
25、环n次,故时间复杂度为O(n)。二叉树的遍历实现层次遍历中序遍历后序遍历前序遍历两个遍历序列确定二叉树二叉树的后序遍历:如果二叉树为空,遍历操作为空。否则,先后序遍历根的左子树,然后后序遍历根的右子树,最后访问根结点。可简记为:“左右根”。下图的后序遍历序列:S、L、F、D、C、B后序遍历的递归算法voidPrintPostOrder(Node*T)/按后序打印以T为根的二叉树的结点的数据值。if(!T)return;PrintPostOrder(T-left);PrintPostOrder(T-right);printf(%c,T-data);将根结点压栈,状态0压栈。如果二叉树为空,遍历结
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 语言 描述 二叉
限制150内