1、数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 1实 验 六 二 叉 树【实验目的】1、掌握二叉树的基本存储表示。2、掌握二叉树的遍历操作实现方法(递归和非递归方法) 。3、理解并实现二叉树的其他基本操作。4、掌握二叉树的重要应用-哈夫曼编码的实现。【实验学时】4-6 学时【实验预习】回答以下问题:1、二叉树的二叉链表存储表示。typedef struct BiTNode / 结点结构 ElemType data ;/数据域struct BiTNode *Lchild ;/左孩子指针 struct BiTNode *Rchild;/右孩子指针 BiTNode ,*BiTre
2、e ;void Create(BiTree /输入一个元素if (ch=# ) T = NULL;else T= (BiTree)malloc(sizeof(BiTNode);/申请根结点T-data =ch; / 给根结点数据域赋值Create(T-Lchild);/建左子树 Create(T-Rchild);/建右子树 / Create2、二叉树的三种基本遍历方式。(1)前序遍历(DLR) ,首先访问根结点,然后遍历左子树,最后遍历右子树。简记根-左-右。(2)中序遍历(LDR) ,首先遍历左子树,然后访问根结点,最后遍历右子树。简记左-根-右。(3)后序遍历(LRD) ,首先遍历左子树,
3、然后遍历右子树,最后访问根结点。简记左-右-根。 数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 23、解释哈夫曼树和带权路径长度 WPL。哈夫曼树:它是最优二叉树。定义:给定 n 个权值作为 n 个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树。路径和路径长度定义:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为 1,则从根结点到第 L 层结点的路径长度为 L-1。结点的权及带权路径长度定义:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路
4、径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。 树的带权路径长度定义:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为 WPL。【实验内容和要求】1、 编写程序 exp6_1.c,实现二叉树的链式存储及基本操作。以下图所示的二叉树实现二叉树的二叉链表存储及基本操作,回答下列问题,补充完整程序,并调试运行验证结果。ABC DE FGA B C D E F G (1)按照先序序列建立该二叉树。读入的字符序列应为:_ABCDEFG_(*表示空指针)。(2)该二叉树的三种遍历序列:先序序列:_ABCDEFG_;中序序列:_CBEGDFA_;后序序列:_CGEFDBA_;(3)按
5、层次遍历该二叉树,得到的序列为:_ABCDEFG_。(4)该二叉树的深度为:_4_。(5)该二叉树的叶子结点数为:_3_。(6)交换该二叉树所有结点的左右次序得到的新二叉树为:(画出新二叉树的图)数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 3(7)新二叉树的三种遍历序列分别为:先序序列:_ABDFEGC_;中序序列:_AFDGEBC_;后序序列:_FGEDCBA_;exp6_1.c 参考程序如下:#include#include#define MAX 20/*-二叉树的二叉链表存储表示-*/typedef struct BTNodechar data ; /*结点数据*
6、/struct BTNode *lchild; /*左孩子指针*/struct BTNode *rchild ; /*右孩子指针*/*BiTree;/*-非递归遍历辅助队列-*/typedef structBiTree dataMAX;int front,rear; queue;void createBiTree(BiTree *t); /*先序遍历创建二叉树*/void PreOrder(BiTree p); /*先序遍历二叉树*/void InOrder(BiTree p); /*中序遍历二叉树*/void PostOrder(BiTree p); /*后序遍历二叉树*/void RPre
7、order(BiTree p); /*先序遍历的非递归算法*/void RInorder(BiTree p); /*中序遍历的非递归算法*/void RPostorder(BiTree p); /*后序遍历的非递归算法*/ABCDEFG数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 4int depth(BiTree t); /*求二叉树的深度算法*/BiTree gettreenode(char x,BiTree lptr,BiTree rptr);/*后序复制二叉树-建立结点*/BiTree copytree(BiTree t); /*以后序遍历的方式复制二叉树*/Bi
8、Tree swap(BiTree b); /*交换二叉树的结点的左右孩子*/void ccOrder(BiTree t); /*利用循环队列实现层次遍历*/int Leaves(BiTree t); /*统计二叉树叶子结点(递归)*/void release(BiTree t); /*释放二叉树*/*先序遍历创建二叉树*/void createBiTree(BiTree *t)char s;BiTree q;printf(“nplease input data:“);s=getchar();getchar(); /*扔掉存在键盘缓冲区的输入结束回车符*/if(s=#) /*子树为空则返回*/*
9、t=NULL;return;q=(BiTree)malloc(sizeof(struct BTNode);if(q=NULL)printf(“Memory alloc failure!“);exit(0);q-data=s;*t=q;createBiTree(/*递归建立左子树*/createBiTree(/*递归建立右子树*/*createBiTree*/*先序遍历二叉树,补充递归算法 */void PreOrder(BiTree p) if(p!=NULL) printf(“%c “,p-data); PreOrder (p-lchild); PreOrder (p-rchild); 数据
10、结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 5/*PreOrder*/*中序遍历二叉树,补充递归算法 */void InOrder(BiTree p)if(p!=NULL) InOrder (p-lchild);printf(“%c “,p-data); InOrder (p-rchild); /*InOrder*/*后序遍历二叉树,补充递归算法 */void PostOrder(BiTree p)if(p!=NULL) PostOrder (p-lchild):PostOrder (p-rchild); printf(“%c “,p-data);/*PostOrder*/
11、*先序遍历的非递归算法*/void RPreorder(BiTree p)BiTree stackMAX,q;int top=0,i;for(i=0; idata);if(q-rchild!=NULL) _stacktop+=q-rchild_; /*右指针进栈*/if(q-lchild!=NULL) q=q-lchild; /*顺着左指针继续向下*/else if(top0) q=stack-top; /*左子树访问完,出栈继续访问右子树结点 */else q=NULL;/*RPreorder*/*中序遍历的非递归算法*/数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 6
12、void RInorder(BiTree p)BiTree stackMAX,q;int top=0,i;for(i=0; irchild!=NULL) _stacktop+=q-rchild_; /*右指针进栈*/if(q-lchild=NULL)printf(“%c“,q-data);else stacktop+=q-lchild; /*左指针进栈*/q=q-lchild; /*顺着左指针继续向下 */else if(top0) q=stack-top; /*左子树访问完,出栈继续访问右子树结点 */else q=NULL;/*RInorder*/*后序遍历的非递归算法*/void RPo
13、storder(BiTree p)BiTree stackMAX,q;int i,top=0,flagMAX;for(i=0; ilchild;else数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 7while(top)if(flagtop-1=0) /*遍历结点的右子树*/q=stacktop-1;q=q-rchild;flagtop-1=1;break;elseq=stack-top;printf(“%c“,q-data); /*遍历结点*/if(top=0) break;/*RPostorder*/*求二叉树的深度算法,补充递归算法 */int depth(BiTr
14、ee t)int rd,ld; if(!t) return 0; else rd=depth(B-lchild); ld=depth(B-rchild); if(rdld) return ld+1; else return rd+1; /*depth*/*建立结点*/BiTree gettreenode(char x,BiTree lptr,BiTree rptr)BiTree t;t=(BiTree)malloc(sizeof(struct BTNode);t- data = x;数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 8t-lchild = lptr;t-rch
15、ild = rptr;return(t);/*gettreenode*/*以后序遍历的方式递归复制二叉树 */BiTree copytree(BiTree t)BiTree newlptr,newrptr,newnode;if(t=NULL)return NULL;if(t-lchild!=NULL)newlptr = copytree(t-lchild);else newlptr = NULL;if(t-rchild!=NULL)newrptr = copytree(t-rchild);else newrptr = NULL;newnode = gettreenode(t-data, new
16、lptr, newrptr);return(newnode);/*copytree*/*交换二叉树的结点的左右孩子 */BiTree swap(BiTree b)BiTree t,t1,t2;if(b=NULL)t=NULL;elset=(BiTree)malloc(sizeof(struct BTNode);t-data=b-data;t1=swap(b-lchild); /*递归交换左子树上的结点*/t2=swap(b-rchild); /*递归交换右子树上的结点*/t-lchild=t2; /*交换根 t 的左右子树*/t-rchild=t1;return(t);/*swap*/*利用循
17、环队列实现层次遍历 */void ccOrder(BiTree t) /*ccOrder*/数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 9/定义队列typedef struct queueBT *base;int front;int rear;queue;/队列实现void QueueStart(queue if(!Q.base)exit(0);Q.front=0;Q.rear=0;void QueueInt(queue Q.baseQ.rear=p;Q.rear=(Q.rear+1)%size;void QueueOut(queue if(Q.rear=Q.front
18、)return ;p=Q.baseQ.front;Q.front=(Q.front+1)%size;/*统计二叉树叶子结点,补充递归算法 */int Leaves(BiTree t,int sum)if(t)if(t-lchild=NULLsum= Leaves (t-lchild,sum);sum= Leaves (t-rchild,sum);数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 10return(sum);/*Leaves*/*释放二叉树*/void release(BiTree t)if(t!=NULL)release(t-lchild);release(t
19、-rchild);free(t);/*release*/int main()BiTree t=NULL,copyt=NULL;int select;doprintf(“n*MENU*n“);printf(“ 1. 按先序序列建立二叉树n“);printf(“ 2. 遍历二叉树(三种递归方法)n“);printf(“ 3. 遍历二叉树(三种非递归方法)n“);printf(“ 4. 层次遍历二叉树n“);printf(“ 5. 输出二叉树的深度n“);printf(“ 6. 统计二叉树的叶子结点数(递归)n“);printf(“ 7. 后序遍历方式复制一棵二叉树n“);printf(“ 8. 交
20、换二叉树所有结点的左右孩子n“);printf(“ 0. EXIT“);数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 11printf(“n*MENU*n“);printf(“ninput choice:“);scanf(“%d“,getchar();switch(select)case 1:printf(“n1-按先序序列建立二叉树:n“);printf(“请依次输入结点序列:n“);createBiTree(if(t!=NULL)printf(“二叉树创建成功!n“);elseprintf(“二叉树未创建成功!n“);break;case 2:printf(“n2-遍
21、历二叉树(三种递归方法):n“);printf(“n 先序遍历序列:“);PreOrder(t);printf(“n 中序遍历序列:“);InOrder(t);printf(“n 后序遍历序列:“);PostOrder(t);printf(“n“);break;case 3:printf(“n3-遍历二叉树(三种非递归方法):n“);printf(“n 先序遍历的非递归:“);RPreorder(t);printf(“n 中序遍历的非递归:“);RInorder(t);printf(“n 后序遍历的非递归:“);RPostorder(t);printf(“n“);break;case 4:pr
22、intf(“n4-层次遍历二叉树:n“);printf(“n 按层次遍历:“);ccOrder(t);printf(“n“);break;case 5:printf(“n5-输出二叉树的深度:n“);printf(“n 二叉树的深度:%d“,depth(t);数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 12printf(“n“);break;case 6:printf(“n6-统计二叉树的叶子结点数(递归):n“);printf(“n 叶子结点数为:%d“,Leaves(t);printf(“n“);break;case 7:printf(“n7-后序遍历方式复制一棵二
23、叉树:n“);copyt=copytree(t);if(copyt!=NULL)printf(“n 先序递归遍历复制的二叉树:“);PreOrder(copyt);elseprintf(“n 复制失败!“);printf(“n“);break;case 8:printf(“n8-交换二叉树所有结点的左右孩子:n“);printf(“n 先序递归遍历交换后的二叉树:“);PreOrder(swap(t);printf(“n“);break;case 0:release(t); /*释放二叉树*/break;default:break;while(select);return 0;2、 编写程序
24、exp6_2.c,实现哈夫曼树的建立和哈夫曼编码。若有一组字符序列a,c,e,i,s,t,w,对应的出现频率为10,1,15,12,3,4,13 。以此序列创建哈夫曼树和哈夫曼编码。回答下列问题,补充完整程序,并调试运行验证结果。(1) 构造该序列的哈夫曼树,画出哈夫曼树的形态。 (以结点值左小右大的原则)数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 13(2) 写出对应的哈夫曼编码。a(111)c(11010)e(10)i(00)s(11011)t(1100)w(01)(3) 计算编码的 WPL。WPL=(1+3)*5+4*4+10*3+(12+13+15)*2=146
25、exp6_2.c 程序代码参考如下:#include#define MAXVALUE 10000 /*定义最大权值*/#define MAXLEAF 30 /*定义哈夫曼树中叶子结点个数*/#define MAXNODE MAXLEAF*2-1#define MAXBIT 10 /*定义哈夫曼编码的最大长度*/58725 33181512 138 104 41 3数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 14typedef struct /*哈夫曼编码结构*/int bitMAXBIT;int start;HCodeType;typedef struct /*哈夫曼树
26、结点结构*/char data;int weight;int parent;int lchild;int rchild;HNodeType;void HuffmanTree(HNodeType HuffNode,int *hn);void HuffmanCode(HNodeType HuffNode,HCodeType HuffCode,int n);void HuffmanTree(HNodeType HuffNode,int *hn)/*哈夫曼树的构造算法*/int i,j,m1,m2,x1,x2,n;printf(“n:“);scanf(“%d“,getchar(); /*输入叶子结点个
27、数*/for (i=0; i2*n-1; i+) /*数组 HuffNode 初始化*/HuffNodei.data=0;HuffNodei.weight=0;HuffNodei.parent=-1;HuffNodei.lchild=-1;HuffNodei.rchild=-1; printf(“HuffNode:n“);for (i=0; in; i+)scanf(“%c,%d“, /*输入 n 个叶子结点的权值*/getchar();for (i=0; in-1; i+) /*构造哈夫曼树*/m1=m2=MAXVALUE;x1=x2=0;数据结构与算法实验指导 V2016常熟理工学院计算机
28、科学与工程学院 15for (j=0; jn+i; j+)if (HuffNodej.weightm1 x2=x1;m1=HuffNodej.weight;x1=j;else if (HuffNodej.weightm2 x2=j;/*将找出的两棵子树合并为一棵子树 */HuffNodex1.parent=n+i;HuffNodex2.parent=n+i;HuffNoden+i.weight= HuffNodex1.weight+HuffNodex2.weight ;HuffNoden+i.lchild=x1;HuffNoden+i.rchild=x2;*hn=n;void HuffmanC
29、ode(HNodeType HuffNode,HCodeType HuffCode,int n) /*生成哈夫曼编码*/HCodeType cd;int i,j,c,p;for(i=0; in; i+) /*求每个叶子结点的哈夫曼编码*/cd.start=n-1;c=i;p=HuffNodec.parent;while(p!=-1) /*由叶结点向上直到树根*/if(HuffNodep.lchild=c)cd.bitcd.start=0; ;/*左分支编码为 0*/elsecd.bitcd.start=1; ; /*右分支编码为 1*/cd.start-;c=p;p=HuffNodec.par
30、ent;数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 16for(j=cd.start+1; jn; j+) /*保存求出的每个叶结点的哈夫曼编码和编码的起始位*/HuffCodei.bitj=cd.bitj;HuffCodei.start=cd.start;for (i=0; in; i+) /*输出每个叶子结点的哈夫曼编码*/printf(“%c: “,HuffNodei.data);for(j=HuffCodei.start+1; jn; j+)printf(“%d“,HuffCodei.bitj);printf(“n“);int main()HNodeType H
31、uffNodeMAXNODE;HCodeType HuffCodeMAXLEAF;int n,i;printf(“create HuffmanTree:n“);HuffmanTree(HuffNode,printf(“n“);for(i=0; i2*n-1; i+)putchar(HuffNodei.data);printf(“%3d“,HuffNodei.weight);printf(“%3d“,HuffNodei.parent);printf(“%3d“,HuffNodei.lchild);printf(“%3d“,HuffNodei.rchild);printf(“n“);printf(“n“);HuffmanCode(HuffNode,HuffCode,n);return 0;【拓展实验】3、 实现哈夫曼的解码功能。在上题的基础上,根据给定的哈夫曼编码译文,进行解码,输出原字符编码。数据结构与算法实验指导 V2016常熟理工学院计算机科学与工程学院 17【实验小结】