《数据结构C语言树和二叉树.pptx》由会员分享,可在线阅读,更多相关《数据结构C语言树和二叉树.pptx(74页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第六章 树和二叉树树是一类重要的非线性数据结构,是以分支关系定义的层次结构6.1 树的定义定义定义:树(tree)是n(n0)个结点的有限集T,其中:有且仅有一个特定的结点,称为树的根(root)当n1时,其余结点可分为m(m0)个互不相交的有限集T1,T2,Tm,其中每一个集合本身又是一棵树,称为根的子树(subtree)特点:树中至少有一个结点根树中各子树是互不相交的集合第1页/共74页A只有根结点的树ABCDEFGHIJKLM有子树的树根子树第2页/共74页基本术语结点(node)表示树中的元素,包括数据项及若干指向其子树的分支结点的度(degree)结点拥有的子树数叶子(leaf)度为
2、0的结点孩子(child)结点子树的根称为该结点的孩子双亲(parents)孩子结点的上层结点叫该结点的兄弟(sibling)同一双亲的孩子树的度一棵树中最大的结点度数结点的层次(level)从根结点算起,根为第一层,它的孩子为第二层深度(depth)树中结点的最大层次数森林(forest)m(m0)棵互不相交的树的集合第3页/共74页ABCDEFGHIJKLM结点A的度:3结点B的度:2结点M的度:0叶子:K,L,F,G,M,I,J结点A的孩子:B,C,D结点B的孩子:E,F结点I的双亲:D结点L的双亲:E结点B,C,D为兄弟结点K,L为兄弟树的度:3结点A的层次:1结点M的层次:4树的深度
3、:4结点F,G为堂兄弟结点A是结点F,G的祖先第4页/共74页第5页/共74页图形表示法:教师教师学生学生其他人员其他人员99级级2000级级2001级级2002级级华中科技大学华中科技大学计算机系计算机系电信系电信系自控系自控系叶子叶子根根子树子树第6页/共74页第7页/共74页第8页/共74页6.2 二叉树定义定义:二叉树是n(n0)个结点的有限集,它或为空树(n=0),或由一个根结点和两棵分别称为左子树和右子树的互不相交的二叉树构成特点每个结点至多有二棵子树(即不存在度大于2的结点)二叉树的子树有左、右之分,且其次序不能任意颠倒基本形态A只有根结点的二叉树空二叉树AB右子树为空AB左子树
4、为空ABC左、右子树均非空第9页/共74页二叉树性质性质1:证明:用归纳法证明之i=1时,只有一个根结点,是对的假设对所有j(1j1,则其双亲是i/2 (2)如果2in,则结点i无左孩子;如果2in,则其左孩子是2i (3)如果2i+1n,则结点i无右孩子;如果2i+1n,则其右孩子是2i+1第14页/共74页二叉树的存储结构顺序存储结构实现:按满二叉树的结点层次编号,依次存放二叉树中的数据元素特点:结点间关系蕴含在其存储位置中浪费空间,适于存满二叉树和完全二叉树abcdefgabcde0000fg1234567891011第15页/共74页链式存储结构二叉链表typedefstructnod
5、edatatypedata;structnode*lchild,*rchild;JD;lchilddatarchildABCDEFG在n个结点的二叉链表中,有n+1个空指针域ABCDEFG空指针个数:2*n0+1*n1+0*n2=2n0+n1=n0+n1+n0=n0+n1+n2+1=n+1第16页/共74页三叉链表typedefstructnodedatatypedata;structnode*lchild,*rchild,*parent;JD;lchilddataparentrchildABCDEFGABCDEFG第17页/共74页6.3 遍历二叉树和线索二叉树二叉树的遍历方法先序遍历:先访
6、问根结点,然后分别先序遍历左子树、右子树中序遍历:先中序遍历左子树,然后访问根结点,最后中序遍历右子树后序遍历:先后序遍历左、右子树,然后访问根结点按层次遍历:从上到下、从左到右访问各结点DLRLDR、LRD、DLRRDL、RLD、DRL第18页/共74页ADBCD L RAD L RD L RBDCD L R先序遍历序列:ABDC先序遍历:第19页/共74页ADBCL D RBL D RL D RADCL D R中序遍历序列:BDAC中序遍历:第20页/共74页ADBC L R DL R DL R DADCL R D后序遍历序列:DBCA后序遍历:B第21页/共74页-+/a*b-efcd先
7、序遍历:中序遍历:后序遍历:层次遍历:-+a*b-c d/e f-+a*b-cd/ef-+a*b-c d/e f-+a*b-c d/e f第22页/共74页算法递归算法第23页/共74页void preorder(JD*bt)if(bt!=NULL)printf(%dt,bt-data);preorder(bt-lchild);preorder(bt-rchild);主程序Pre(T)返回返回pre(TR);返回返回pre(TR);ACBDTBprintf(B);pre(TL);BTAprintf(A);pre(TL);ATDprintf(D);pre(TL);DTCprintf(C);pre
8、(TL);C返回T左是空返回pre(TR);T左是空返回T右是空返回T左是空返回T右是空返回pre(TR);先序序列:ABDC第24页/共74页非递归算法ABCDEFGpiP-A(1)ABCDEFGpiP-AP-B(2)ABCDEFGpiP-AP-BP-C(3)p=NULLABCDEFGiP-AP-B访问:C(4)第25页/共74页pABCDEFGiP-A访问:CB(5)ABCDEFGiP-AP-D访问:CBp(6)ABCDEFGiP-AP-DP-E访问:CBp(7)ABCDEFGiP-AP-D访问:CBEp(8)第26页/共74页ABCDEFGiP-AP-DP-G访问:CBEP=NULL(9
9、)ABCDEFGiP-A访问:CBEGDp(11)ABCDEFGiP-AP-F访问:CBEGDp(12)ABCDEFGiP-AP-D访问:CBEGp(10)第27页/共74页ABCDEFGiP-A访问:CBEGDFp=NULL(13)ABCDEFGi访问:CBEGDFAp(14)ABCDEFGi访问:CBEGDFAp=NULL(15)后序遍历非递归算法第28页/共74页遍历算法应用按先序遍历序列建立二叉树的二叉链表,已知先序序列为:ABCDEGF求二叉树深度算法ABCDEFGABCDEFG统计二叉树中叶子结点个数算法二叉树的建立演示第29页/共74页用队列实现层次遍历下面的C语言函数是实现对给
10、定的二叉树T的层次遍历。函数使用一个顺序存储的队列q100,存放还没有处理的子树的根结点的地址。注意,队首和队尾指针分别指向队首结点和下次进队结点的存放位置。voidlev_traverse(T)NODE*T;NODE*q100,p;inthead,tail,i;q0=T;head=0;tail=1;while(headdata);if(p-lchild!=NULL)qtail+=p-lchild;if(p-rchild!=NULL)qtail+=p-rchild;第30页/共74页线索二叉树定义:前驱与后继:在二叉树的先序、中序或后序遍历序列中两个相邻的结点互称为线索:指向前驱或后继结点的指
11、针称为线索二叉树:加上线索的二叉链表表示的二叉树叫线索化:对二叉树按某种遍历次序使其变为线索二叉树的过程叫实现在有n个结点的二叉链表中必定有n+1个空链域在线索二叉树的结点中增加两个标志域ltag:若ltag=0,lchild域指向左孩子;若ltar=1,lchild域指向其前驱rtag:若rtag=0,rchild域指向右孩子;若rtag=1,rchild域指向其后继第31页/共74页ABCDEABDCET先序序列:ABCDE先序线索二叉树00001111 11typedefstructnodeintdata;intltag,rtag;structnode*lchild,*rchild;JD
12、;lchildltagdatartagrchild第32页/共74页ABCDEABDCET中序序列:BCAED中序线索二叉树0000111111第33页/共74页ABCDEABDCET后序序列:CBEDA后序线索二叉树0000111111第34页/共74页ABCDE0A01B00D11C11E1T中序序列:BCAED带头结点的中序线索二叉树01头结点:ltag=0,lchild指向根结点rtag=1,rchild指向遍历序列中最后一个结点遍历序列中第一个结点的lchild域和最后一个结点的rchild域都指向头结点ABDCET中序序列:BCAED中序线索二叉树0000111111第35页/共7
13、4页线索二叉树的生成算法(算法6.6,见教材P134)目的:在依某种顺序遍历二叉树时修改空指针,添加前驱或后继。目的:在依某种顺序遍历二叉树时修改空指针,添加前驱或后继。注解:为方便添加结点的前驱或后继,需要设置两个指针:注解:为方便添加结点的前驱或后继,需要设置两个指针:p指针指针当前结点之指针;当前结点之指针;pre指针指针前驱结点之指针。前驱结点之指针。技巧:当结点技巧:当结点p的左的左/右域为空时,只改写它的左域(装入前驱右域为空时,只改写它的左域(装入前驱pre),而其右域(后),而其右域(后继)留给下一结点来填写。继)留给下一结点来填写。或者说,当前结点的指针或者说,当前结点的指针
14、p应当送到前驱结点的空右域中。应当送到前驱结点的空右域中。若若p-lchildNULL,则则p-Ltag=1;p-lchildp-Ltag=1;p-lchildpre;pre;/p /p的前驱结点指针的前驱结点指针prepre存入左空域存入左空域若若pre-rchildNULL,则则pre-Rtagpre-Rtag1;pre-rchild=p;1;pre-rchild=p;/p /p存入其前驱结点存入其前驱结点prepre的右空域的右空域第36页/共74页算法遍历中序线索二叉树在中序线索二叉树中找结点后继的方法:(1)若rtag=1,则rchild域直接指向其后继(2)若rtag=0,则结点的
15、后继应是其右子树的左链尾(ltag=1)的结点在中序线索二叉树中找结点前驱的方法:(1)若ltag=1,则lchild域直接指向其前驱(2)若ltag=0,则结点的前驱应是其左子树的右链尾(rtag=1)的结点ABCDE0A01B00D11C11E1T中序序列:BCAED带头结点的中序线索二叉树01第37页/共74页程序注解 (非递归,且不用栈非递归,且不用栈):P=T-lchild;/从头结点进入到根结点;从头结点进入到根结点;while(p!=T)while(p-LTag=link)p=p-lchild;/先找到中序遍历起点先找到中序遍历起点if(!visit(p-data)returnE
16、RROR;/若起点值为空则出错告警若起点值为空则出错告警while(p-RTag=Thread)p=p-rchild;Visit(p-data);/若有后继标志,则直接提取若有后继标志,则直接提取p-rchild中线索并访问后继结点;中线索并访问后继结点;p=p-rchild;/当前结点右域不空或已经找好了后继,则一律从结点的右子树开始重当前结点右域不空或已经找好了后继,则一律从结点的右子树开始重复复 的全部过程。的全部过程。ReturnOK;线索二叉树的中序遍历算法(算法6.5,参见教材P134)LTag=0RTag=1第38页/共74页中序线索化演示中序线索化后续演示中序线索化前序演示第3
17、9页/共74页6.4 树的存储结构树的存储结构双亲表示法实现:定义结构数组存放树的结点,每个结点含两个域:数据域:存放结点本身信息双亲域:指示本结点的双亲结点在数组中位置特点:找双亲容易,找孩子难typedefstructnodedatatypedata;intparent;JD;JDtM;第40页/共74页abcdefhgiacdefghib012235551096012345789dataparent0号单元不用或存结点个数如何找孩子结点第41页/共74页孩子表示法多重链表:每个结点有多个指针域,分别指向其子树的根结点同构:结点的指针个数相等,为树的度D结点不同构:结点指针个数不等,为该结
18、点的度ddatachild1child2.childDdatadegreechild1child2.childd孩子链表:每个结点的孩子结点用单链表存储,再用含n个元素的结构数组指向每个孩子链表第42页/共74页孩子结点:typedefstructnodeintchild;/该结点在表头数组中下标structnode*next;/指向下一孩子结点JD;表头结点:typedefstructtnodedatatypedata;/数据域structnode*fc;/指向第一个孩子结点TD;TDtM;/t0不用第43页/共74页abcdefhgi6012345789acdefghibdata fc23
19、459786如何找双亲结点第44页/共74页带双亲的孩子链表612345789acdefghibdatafc23459786012235551parentabcdefhgi第45页/共74页孩子兄弟表示法(二叉树表示法)实现:用二叉链表作树的存储结构,链表中每个结点的两个指针域分别指向其第一个孩子结点和下一个兄弟结点特点操作容易破坏了树的层次typedefstructnodedatatypedata;structnode*fch,*nsib;JD;abcdefhgiabcdefghi第46页/共74页树与二叉树转换ACBED树ABCDE二叉树ABCDEABCDEABCDE对应存储存储解释解释第
20、47页/共74页将树转换成二叉树加线:在兄弟之间加一连线抹线:对每个结点,除了其左孩子外,去除其与其余孩子之间的关系旋转:以树的根结点为轴心,将整树顺时针转45ABCDEFGHIABCDEFGHIABCDEFGHIABCDEFGHIABCDEFGHI树转换成的二叉树其右子树一定为空第48页/共74页将二叉树转换成树加线:若p结点是双亲结点的左孩子,则将p的右孩子,右孩子的右孩子,沿分支找到的所有右孩子,都与p的双亲用线连起来抹线:抹掉原二叉树中双亲与右孩子之间的连线调整:将结点按层次排列,形成树结构ABCDEFGHIABCDEFGHIABCDEFGHIABCDEFGHIABCDEFGHI第49
21、页/共74页森林转换成二叉树将各棵树分别转换成二叉树将每棵树的根结点用线相连以第一棵树根结点为二叉树的根,再以根结点为轴心,顺时针旋转,构成二叉树型结构ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ第50页/共74页二叉树转换成森林抹线:将二叉树中根结点与其右孩子连线,及沿右分支搜索到的所有右孩子间连线全部抹掉,使之变成孤立的二叉树还原:将孤立的二叉树还原成树ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ第51页/共74页树和森林的遍历树的遍历遍历按一定规律走遍树的各个顶点,且使每一顶点仅被访问一次,即找一个完整而有规律的走法
22、,以得到树中所有结点的一个线性排列常用方法先根(序)遍历:先访问树的根结点,然后依次先根遍历根的每棵子树后根(序)遍历:先依次后根遍历每棵子树,然后访问根结点按层次遍历:先访问第一层上的结点,然后依次遍历第二层,第n层的结点第52页/共74页ABCDEFGHIJKLMNO先序遍历:后序遍历:层次遍历:A B E F IG C D H J K L N O ME I F G B C J K N O L M H D AA B C D E F G H I J K L M N O第53页/共74页讨论:若采用讨论:若采用“先转换,后遍历先转换,后遍历”方式,结果是否一样方式,结果是否一样?abdec先序
23、遍历:先序遍历:后序遍历:后序遍历:中序遍历:中序遍历:d e c b aabdeca b c d eb d c e a1.树的先序遍历二法相同;树的先序遍历二法相同;2.树的后序遍历相当于对应二叉树的中序遍历;树的后序遍历相当于对应二叉树的中序遍历;3.树没有中序遍历,因为子树无左右之分。树没有中序遍历,因为子树无左右之分。结论:结论:第54页/共74页先序遍历先序遍历F若森林为空,返回;若森林为空,返回;F访问森林中第一棵树的根结点;访问森林中第一棵树的根结点;F先序遍历第一棵树中根结点的子树森林;先序遍历第一棵树中根结点的子树森林;F先序遍历除去第一棵树之后剩余的树构成的森林。先序遍历除
24、去第一棵树之后剩余的树构成的森林。中序遍历中序遍历F若森林为空,返回;若森林为空,返回;F中序遍历森林中第一棵树的根结点的子树森林;中序遍历森林中第一棵树的根结点的子树森林;F访问第一棵树的根结点;访问第一棵树的根结点;F中序遍历除去第一棵树之后剩余的树构成的森林。中序遍历除去第一棵树之后剩余的树构成的森林。森林的遍历森林的遍历ABCDEFGHJI第55页/共74页讨论:讨论:若采用若采用“先转换,后遍历先转换,后遍历”方式,结果是否相同方式,结果是否相同?例如:例如:A AB BC CD DE EF FGGH HJ JI I先序序列:先序序列:中序序列:中序序列:A B C D E F G
25、H I JB C D A F E H J I GA AB BC CD DE EF FGGH HJ JI I先序序列:先序序列:中序序列:中序序列:A B C D E F G H I JB C D A F E H J I G结论:森林的先序和中序遍历在结论:森林的先序和中序遍历在两种方式下的结果相同。两种方式下的结果相同。第56页/共74页结论:当以二叉链表做树的存储结构时,树的先结论:当以二叉链表做树的存储结构时,树的先根序列和后根序列可借用二叉树的先序遍历和后根序列和后根序列可借用二叉树的先序遍历和后序遍历的算法实现之;对于森林也一样。序遍历的算法实现之;对于森林也一样。第57页/共74页一
26、、基本术语基本术语1路径和路径长度路径和路径长度在一棵树中,从一个结点往下可以达到的孩子或子孙结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。2结点的权及带权路径长度结点的权及带权路径长度若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。7.7 哈夫曼树第58页/共74页3树的带权路径长度树的带权路径长度树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为wpl=,其中n为叶子结点数目,wi为第i个叶子结点的权值,li为第i个叶
27、子结点的路径长度。二、构造哈夫曼树1哈夫曼树的定义哈夫曼树的定义在一棵二叉树中,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffmantree)。第59页/共74页例有4个结点,权值分别为7,5,2,4,构造有4个叶子结点的二叉树abcd7524WPL=7*2+5*2+2*2+4*2=36dcab2475WPL=7*3+5*3+2*1+4*2=46abcd7524WPL=7*1+5*2+2*3+4*3=35第60页/共74页2哈夫曼树的构造哈夫曼树的构造假设有n个权值,则构造出的哈夫曼树有n个叶子结点。n个权值分别设为w1,w2,wn,则哈夫曼树的构造规则为:(1)
28、将w1,w2,wn看成是有n棵树的森林(每棵树仅有一个结点);(2)在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;(3)从森林中删除选取的两棵树,并将新树加入森林;(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为我们所求得的哈夫曼树。第61页/共74页下面给出哈夫曼树的构造过程,假设给定的叶子结点的权分别为1,5,7,3,则构造哈夫曼树过程如图7-24所示。第62页/共74页从图7-24可知,n个权值构造哈夫曼树需n-1次合并,每次合并,森林中的树数目减1,最后森林中只剩下一棵树,即为我们求得的哈夫曼树。构造哈
29、夫曼树的模拟演示第63页/共74页3 3、哈夫曼树构造程序、哈夫曼树构造程序 一棵有n个叶子结点的Huffman树有2n-1个结点采用顺序存储结构一维结构数组存储结点信息结点类型定义为:typedefstructintweight;intparent,lchild,rchild;JD;#defineMAX100voidhuffman(intn,intw,JDt)inti,j,k,x1,x2,m1,m2;for(i=1;i(2*n);i+)ti.parent=ti.lchild=ti.rchild=-1;if(i=n)ti.weight=wi;elseti.weight=0;第64页/共74页f
30、or(i=1;in;i+)m1=m2=MAX;x1=x2=0;for(j=1;j(n+i);j+)if(tj.weightm1)&(tj.parent=0)m2=m1;x2=x1;m1=tj.weight;x1=j;elseif(tj.weightm2)&(tj.parent=0)m2=tj.weight;x2=j;k=n+i;tx1.parent=tx2.parent=k;tk.weight=m1+m2;tk.lchild=x1;tk.rchild=x2;第65页/共74页哈夫曼树的算法模拟演示第66页/共74页 在远程通讯中,要将待传字符转换成由二进制组成的字符串:设要传送的字符为:ABA
31、CCDA若编码为:A00B01C10D-11 若将编码设计为长度不等的二进制编码,即让待传字符串中出现次数较多的字符采用尽可能短的编码,则转换的二进制字符串便可能减少。00010010101100三、哈夫曼树的应用(哈夫曼编码哈夫曼编码)第67页/共74页设要传送的字符为:ABACCDA若编码为:A0B00C1D-01 关键:要设计长度不等的编码,则必须使任一字符的编码都不是另一个字符的编码的前缀。这种编码称作前缀编码。ABACCDA000011010但:0000AAAAABABB重码第68页/共74页设要传送的字符为:ABACCDA若编码为:A0B110C10D-111 0110010101
32、110ACBD000111采用二叉树设计二进制前缀编码规定:左分支用“0”表示;右分支用“1”表示第69页/共74页译码过程:分解接收字符串:遇“0”向左,遇“1”向右;一旦到达叶子结点,则译出一个字符,反复由根出发,直到译码完成。0110010101110ACBD000111ABACCDA第70页/共74页求Huffman编码:由叶子根,若:(1)从左分支下去,则分支为“0”;(2)从右分支下去,则分支为“1”。ACBD000111第71页/共74页例:已知某系统在通讯时,只出现C,A,S,T,B五种字符,它们出现的频率依次为2,4,2,3,3,试设计Huffman编码。W(权)=2,4,2,3,3,叶子结点个数n=5 148464220001113301构造的Huffman树TBACS第72页/共74页例:已知某系统在通讯时,只出现C,A,S,T,B五种字符,它们出现的频率依次为2,4,2,3,3,试设计Huffman编码。由Huffman树得Huffman编码为:TBACS000110110111148464220001113301TBACS出现频率越大的字符,其Huffman编码越短。第73页/共74页谢谢您的观看!第74页/共74页