1、数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 1常熟理工学院数据结构与算法实验指导与报告书_2017-2018_学年 第_1_ 学期专 业: 物联网工程 实验名称: 二叉树 实验地点: N6-210 指导教师: 聂盼红 计算机科学与工程学院2017数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 2实 验 六 二 叉 树【实验目的】1、掌握二叉树的基本存储表示。2、掌握二叉树的遍历操作实现方法(递归和非递归方法) 。3、理解并实现二叉树的其他基本操作。4、掌握二叉树的重要应用-哈夫曼编码的实现。【实验学时】4-6 学时【实验预习】回答以下问题:1、二叉树
2、的二叉链表存储表示。/*-二叉树的二叉链表存储表示-*/typedef struct BTNodechar data ; /*结点数据*/struct BTNode *lchild; /*左孩子指针*/struct BTNode *rchild ; /*右孩子指针*/*BiTree;2、二叉树的三种基本遍历方式。/*先序遍历二叉树,补充递归算法 */void PreOrder(BiTree p)if(p!=NULL);printf(“%c“,p-data); /访问根节点PreOrder(p-lchild); /先序遍历左子数PreOrder(p-rchild); /先序遍历右子数/*PreO
3、rder*/*中序遍历二叉树,补充递归算法 */void InOrder(BiTree p)if(p!=NULL);InOrder(p-lchild); /中序遍历左子数数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 3printf(“%c“,p-data); /访问根节点InOrder(p-rchild); /中序遍历右子数/*InOrder*/*后序遍历二叉树,补充递归算法 */void PostOrder(BiTree p)if(p!=NULL);PostOrder(p-lchild); /后序遍历左子数PostOrder(p-rchild); /后序遍历右子数pri
4、ntf(“%c“,p-data); /访问根节点/*PostOrder*/3、解释哈夫曼树和带权路径长度 WPL。哈夫曼树,是指权值为 W1、W2、.Wn 的 n 个叶节点所构成的二叉树中带权路径长度最小的二叉树。从树根结点到到该结点之间的路径长度与该结点上权的乘积称为结点的带权路径长度,通常记作:WPL=(n,i=1)WiLi【实验内容和要求】1、 编写程序 exp6_1.c,实现二叉树的链式存储及基本操作。以下图所示的二叉树实现二叉树的二叉链表存储及基本操作,回答下列问题,补充完整程序,并调试运行验证结果。ABC DE FGA B C D E F G (1)按照先序序列建立该二叉树。读入的
5、字符序列应为:A,B,C,*,*,D,E,*,G,*,*,F,*,*,* (*表示空指针)。(2)该二叉树的三种遍历序列:先序序列:A,B,C,D,E,G,F;中序序列:C,B,E,G,D,F,A;后序序列:C,G,E,F,D,B,A;(3)按层次遍历该二叉树,得到的序列为:A,B,C,D,E,F,G(4)该二叉树的深度为 5 。数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 4(5)该二叉树的叶子结点数为:_3_。(6)交换该二叉树所有结点的左右次序得到的新二叉树为:(画出新二叉树的图)(7)新二叉树的三种遍历序列分别为:先序序列:A,B,D,C,F,G,E;中序序列:D
6、,B,F,G,C,E,A;后序序列:D,G,F,E,C,B,A;exp6_1.c 参考程序如下:#include#include#define MAX 20/*-二叉树的二叉链表存储表示-*/typedef struct BTNodechar data; /*结点数据*/struct BTNode *lchild; /*左孩子指针*/struct BTNode *rchild ; /*右孩子指针*/ * BiTree;/*-非递归遍历辅助队列-*/typedef struct SqQueueBiTree dataMAX;int front,rear; SqQueue;void createBi
7、Tree(BiTree *t); /*先序遍历创建二叉树*/void PreOrder(BiTree p); /*先序遍历二叉树*/void InOrder(BiTree p); /*中序遍历二叉树*/ABD CF EG数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 5void PostOrder(BiTree p); /*后序遍历二叉树*/void RPreorder(BiTree p); /*先序遍历的非递归算法*/void RInorder(BiTree p); /*中序遍历的非递归算法*/void RPostorder(BiTree p); /*后序遍历的非递归算法
8、*/int depth(BiTree t); /*求二叉树的深度算法*/BiTree gettreenode(char x,BiTree lptr,BiTree rptr);/*后序复制二叉树-建立结点*/BiTree copytree(BiTree t); /*以后序遍历的方式复制二叉树*/BiTree swap(BiTree b); /*交换二叉树的结点的左右孩子*/void ccOrder(BiTree t); /*利用循环队列实现层次遍历*/int Leaves(BiTree t); /*统计二叉树叶子结点(递归)*/void release(BiTree t); /*释放二叉树*/*
9、先序遍历创建二叉树*/void createBiTree(BiTree * t)char s;BiTree q;printf(“nplease input data:“);s=getchar();getchar(); /*扔掉存在键盘缓冲区的输入结束回车符*/if(s=#) /*子树为空则返回*/* t =NULL;return;elseq=(BiTree)malloc(sizeof(struct BTNode);if(q=NULL)printf(“Memory alloc failure!“);exit(0);q-data=s;*t=q;createBiTree(/*递归建立左子树*/cre
10、ateBiTree(/*递归建立右子树*/*createBiTree*/*先序遍历二叉树,补充递归算法 */void PreOrder(BiTree p)数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 6if(p!=NULL)printf(“%c“,p-data); /访问根节点PreOrder(p-lchild); /先序遍历左子数PreOrder(p-rchild); /先序遍历右子数/*PreOrder*/*中序遍历二叉树,补充递归算法 */void InOrder(BiTree p)if(p!=NULL)InOrder(p-lchild); /中序遍历左子数prin
11、tf(“%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*/*先序遍历的非递归算法*/void RPreorder(BiTree p)BiTree stackMAX,q;int top=0,i;for(i=0; idata);if(q-
12、rchild!=NULL)stacktop+=q-rchild; /*右指针进栈*/数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 7if(q-lchild!=NULL)q=q-lchild; /*顺着左指针继续向下*/elseif(top0)q=stack-top; /*左子树访问完,出栈继续访问右子树结点*/elseq=NULL;/*RPreorder*/*中序遍历的非递归算法*/void RInorder(BiTree p)BiTree stackMAX,q; /定义节点栈和搜索指针int top=0;q=p;dowhile(q)/左链所有节点入栈stacktop+=
13、q;q=q-lchild;if(top0)q=stack-top;printf(“%c“,q-data); /访问根q=q-rchild;while(q|top!=0);/*RInorder*/*后序遍历的非递归算法*/void RPostorder(BiTree p)BiTree stackMAX,q;int i,top=0,flagMAX;for(i=0; ilchild;elsewhile(top)if(flagtop-1=0) /*遍历结点的右子树*/q=stacktop-1;q=q-rchild;flagtop-1=1;break;elseq=stack-top;printf(“%c
14、“,q-data); /*遍历结点*/if(top=0) break;/*RPostorder*/*求二叉树的深度算法,补充递归算法 */int depth(BiTree t) int lc,rc;if(t=NULL)return 0; /若为空树,则返回零elselc=depth(t-lchild); /递归求 t 的左子树深度rc=depth(t-rchild);/递归求 t 的右子树深度if(lcrc)return(lc+1);elsereturn(rc+1);数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 9/*depth*/*建立结点*/BiTree gettre
15、enode(char x,BiTree lptr,BiTree rptr)BiTree t;t=(BiTree)malloc(sizeof(struct BTNode);t- data = x;t-lchild = lptr;t-rchild = 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);el
16、se newlptr = NULL;if(t-rchild!=NULL)newrptr = copytree(t-rchild);else newrptr = NULL;newnode = gettreenode(t-data, newlptr, 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-lc
17、hild); /*递归交换左子树上的结点*/数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 10t2=swap(b-rchild); /*递归交换右子树上的结点*/t-lchild=t2; /*交换根 t 的左右子树*/t-rchild=t1;return(t);/*swap*/*利用循环队列实现层次遍历 */void ccOrder(BiTree t)BiTree p;SqQueue qlist,*q; /利用循环队列,实现层次遍历q=q-rear=0;q-front=0; /初始化队列p=t;if(p!=NULL)printf(“%c“,p-data); /访问根节点q
18、-dataq-rear=p; /根节点入队q-rear=(q-rear+1)%MAX; /修改队尾指针while(q-front!=q-rear)p=q-dataq-front; /出队操作q-front=(q-front+1)%MAX;if(p-lchild!=NULL) /访问出队节点的左孩子,并且入队printf(“%c“,p-lchild-data);q-dataq-rear=p-lchild;q-rear=(q-rear+1)%MAX;if(p-rchild!=NULL) /访问出队节点的右孩子,并且入队printf(“%c“,p-rchild-data);q-dataq-rear=
19、p-rchild;q-rear=(q-rear+1)%MAX;/*ccOrder*/*统计二叉树叶子结点,补充递归算法 */int Leaves(BiTree t)数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 11if(t=NULL)return 0;if(t-lchild=NULLreturn (Leaves(t-lchild)+Leaves(t-rchild); /左子数叶子节点加上右子数叶子结点数/*Leaves*/*释放二叉树*/void release(BiTree t)if(t!=NULL)release(t-lchild);release(t-rchild)
20、;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. 交换二叉树所有结点
21、的左右孩子n“);printf(“ 0. EXIT“);printf(“n*MENU*n“);printf(“ninput choice:“);scanf(“%d“,getchar();switch(select)case 1:printf(“n1-按先序序列建立二叉树:n“);数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 12printf(“请依次输入结点序列:n“);/ BiTree gettreenode(x,createBiTree(if(t!=NULL)printf(“二叉树创建成功!n“);elseprintf(“二叉树未创建成功!n“);break;case
22、 2:printf(“n2-遍历二叉树(三种递归方法):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“);
23、break;case 4:printf(“n4-层次遍历二叉树:n“);printf(“n 按层次遍历:“);ccOrder(t);printf(“n“);break;case 5:printf(“n5-输出二叉树的深度:n“);printf(“n 二叉树的深度:%d“,depth(t);printf(“n“);break;case 6:printf(“n6-统计二叉树的叶子结点数(递归):n“);printf(“n 叶子结点数为:%d“,Leaves(t);printf(“n“);break;数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 13case 7:printf(
24、“n7-后序遍历方式复制一棵二叉树: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;defaul
25、t:break;while(select);return 0;exp6_1.c 实验结果:(1) 按照先序序列建立二叉树:数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 14(2)该二叉树的三种递归遍历序列为:(3)遍历二叉树(三种非递归方法):(4)层次遍历二叉树:(5)输出二叉树的深度数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 15(6)统计二叉树的叶子结点数(递归)(7)后序遍历方式复制一棵二叉树(8)交换二叉树所有结点的左右孩子2、 编写程序 exp6_2.c,实现哈夫曼树的建立和哈夫曼编码。若有一组字符序列a,c,e,i,s,t,w,对应的
26、出现频率为10,1,15,12,3,4,13 。以此序列创建哈夫曼树和哈夫曼编码。回答下列问题,补充完整程序,并调试运行验证结果。(1) 构造该序列的哈夫曼树,画出哈夫曼树的形态。 (以结点值左小右大的原则)e数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 16T658t28T425i12T533e15 T318w13s 3c1t4T14a 10(2) 写出对应的哈夫曼编码。a 的编码为 111, c 的编码为 11000,e 的编码为 10,i 的编码为 00,s 的编码为 11001,t 的编码为 1101,w 的编码为 01(3) 计算编码的 WPL。WPL=3*10
27、+5*1+2*15+2*12+5*3+4*4+2*13=146exp6_2.c 程序代码参考如下:#include#define MAXVALUE 10000 /*定义最大权值*/#define MAXLEAF 30 /*定义哈夫曼树中叶子结点个数*/#define MAXNODE MAXLEAF*2-1#define MAXBIT 10 /*定义哈夫曼编码的最大长度*/typedef struct /*哈夫曼编码结构*/int bitMAXBIT;int start;数据结构与算法实验指导 V2017常熟理工学院计算机科学与工程学院 17HCodeType;typedef struct /*
28、哈夫曼树结点结构*/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(); /*输入叶子结点个数*/for (i=0; ilchild); count2=Leaves(t-rchild); return count1+count2; 在网上查阅资料后明白了其意思,即:左子数的叶子节点数加上右子数的叶子节点数。通过在网上的查阅原来代码还可以这样写:return Leaves(t-lchild)+Leaves(t-rchild);