【二叉树系列】二叉树课程大作业

来源:互联网 发布:长期成本 知乎 编辑:程序博客网 时间:2024/05/16 13:05

本博客将以代码的形式详细讲解二叉树的所有算法,包括创建二叉树,二叉树的三种遍历方式,二叉树的各种属性算法,如:求高度,求叶子节点数,求节点数,以及二叉树最常见的应用哈夫曼树,代码如下:

# include<stdio.h># include<string.h># include<conio.h># include<stdlib.h># define N 1# define M 2*N-1typedef char * HC[N+1];typedef struct bt{char x;struct bt *lchild;struct bt *rchild;}bt,*pbt;typedef struct {int parent;int weight, lchild, rchild;}HT[M+1];void creatbt(pbt *root){char ch=getchar();if(ch==' ')*root=NULL;else{*root=(pbt)malloc(sizeof(bt));(*root)->x=ch;creatbt(&((*root)->lchild));creatbt(&((*root)->rchild));}}void preorder(pbt root){if(root!=NULL){printf("%c",root->x);preorder(root->lchild);preorder(root->rchild);}}void inorder(pbt root){if(root!=NULL){inorder(root->lchild);printf("%c",root->x);inorder(root->rchild);}}void postorder(pbt root){if(root!=NULL){postorder(root->lchild);postorder(root->rchild);printf("%c",root->x);}}int btdepth(pbt root,int h){static int depth=0;if(root!=NULL){if(h>depth) depth=h;btdepth(root->lchild,h+1);btdepth(root->rchild,h+1);}return depth;}int nodenum(pbt root){static int n=0;if(root!=NULL){ n++;nodenum(root->lchild);nodenum(root->rchild);}return n;}int leafnum(pbt root){static int n=0;if(root!=NULL){leafnum(root->lchild);leafnum(root->rchild);if((root->lchild==NULL)&&(root->rchild==NULL))n++;}return n;}void select(HT ht,int n,int *x,int *y){int i,min1=100,min2=200;for(i=1;i<=n;i++){if(ht[i].parent==0&&ht[i].weight<min1){min1=ht[i].weight;*x=i;}}for(i=1;i<=n;i++){if(ht[i].parent==0&&ht[i].weight<min2&&i!=*x){min2=ht[i].weight;*y=i;}}}void hafuman(HT ht,int w[],int n){int i,k,m,x,y;for(i=1;i<=n;i++){ht[i].weight=w[i];ht[i].parent=ht[i].lchild=ht[i].rchild=0;}m=2*n-1;for(i=n+1;i<=m;i++){ht[i].parent=ht[i].lchild=ht[i].rchild=0;}for(i=n+1;i<=m;i++){select(ht,i-1,&x,&y);//选择parent为0且权值最小的结点ht[i].weight=ht[x].weight+ht[y].weight;ht[i].lchild=x;ht[i].rchild=y;ht[x].parent=ht[y].parent=i;}}void hafumancode(HT ht,HC hc,int n){int i,c,p,start;char * cd=(char *)malloc(n*sizeof(char));cd[n-1]='\0';//此处的cd用来存储当前哈夫曼码,可供循环利用,相当于一个暂存器for(i=1;i<=n;i++)//求n个叶子结点的哈夫曼码{start=n-1;c=i;//因为下面会循环更新孩子结点,所以不能用i(否则第一次for循环后i可能就不再是1),可将i的值提前赋给cp=ht[i].parent;while(p!=0)//只要p不是根结点{start--;//此语句用来循环更新存储下标if(ht[p].lchild==c)//cd[i]='0';//错误。注意应从叶子结点开始向上推cd[start]='0';else//cd[i]='1';cd[start]='1';c=p;//此语句用来循环更新孩子结点p=ht[p].parent;}hc[i]=(char *)malloc((n-start)*sizeof(char));strcpy(hc[i],&cd[start]);}free(cd);for(i=1;i<=n;i++){//printf("%d的哈夫曼码为%s\n",ht[i],hc[i]);错误,ht[i]为结构数组,应写其成员printf("%d的哈夫曼码为%s\n",ht[i].weight,hc[i]);}}void main(){int n;pbt root;printf("\t\t-----------------------------------------\n");printf("\t\t1.创建二叉树          2.遍历二叉树\n");printf("\t\t3.二叉树的属性        4.哈夫曼树\n");printf("\t\t5.退出\n");printf("\t\t-----------------------------------------\n");while(1){printf("请选择功能模块(1-5)\n");scanf("%d",&n);//char ch=getche();getchar();switch(n){case 1:{printf("请以先序扩展创建二叉树(空结点用空格代替)\n");creatbt(&root);}break;case 2:{printf("遍历二叉树\n");printf("\t\t[1]先序遍历\n");printf("\t\t[2]中序遍历\n");printf("\t\t[3]后序遍历\n");printf("\t\t[4]返回主菜单\n");while(1){int n;printf("请选择(1-4):\n");scanf("%d",&n);if(1==n)preorder(root);if(2==n)inorder(root);if(3==n)postorder(root);//else//不能这样写,因为这个else只能与上一个if配对,所以当n!=3时break都会执行if(n==4)break;}   }break;case 3:{int h=1,n;printf("二叉树属性\n");printf("\t\t[1]二叉树高度\n");printf("\t\t[2]二叉树结点数\n");printf("\t\t[3]二叉树叶子结点\n");printf("\t\t[4]返回主菜单\n");while(1){printf("请选择:(1-4)\n");scanf("%d",&n);if(1==n)printf("该二叉树的高度为%d\n",btdepth(root,h));if(2==n)printf("该二叉树的结点数为%d\n",nodenum(root));if(3==n)printf("该二叉树的叶子结点数为%d\n",leafnum(root));if(n==4)break;}}break;case 4:{HT ht;HC hc;int n,i;printf("请输入叶子结点的个数\n");scanf("%d",&n);int * w=(int *)malloc((n+1)*sizeof(int));//此语句必须位于scanf的下面for(i=1;i<=n;i++){printf("请输入第%d个叶子结点的权值\n",i);scanf("%d",&w[i]);}hafuman(ht,w,n);hafumancode(ht,hc,n);}break;case 5:exit(1);}}}

程序运行结果如下:




注意对于同一个二叉树,哈夫曼码的结果不唯一,上述输出只是一种情况。

2 0
原创粉丝点击