哈夫曼树是一个很经典的问题,本文输入是一串数字,然后输出生成哈夫曼树的中序遍历结果
#include <stdio.h> #include <stdlib.h> typedef struct node//每个树的节点至少包含3个内容,节点的权值,左子树,右子树的地址 { int element; struct node *Lchild,*Rchild; }node; typedef struct tree { struct node *root; }tree;//每一棵树都是由一个个节点构成的 void Maketree(tree *bt,int x,tree *Lt,tree *Rt)//该函数的目的是传入x的值,建立一棵左子树是Lt,右子树是Rt的树bt(创建方法就是先申请一个空间保存权值,然后记录下左子树右子树的地址,此时注意访问子树有两种方式: //1直接通过左子树Lt->root来访问2通过p->Lchild来访问,而事实上,我们希望的是第二种方式,即这时左子树已经成为整体的一部分,所以都要清零( Lt->root=Rt->root=NULL;) { node *p=(node*)malloc(sizeof(node)); p->element=x; p->Lchild=Lt->root; p->Rchild=Rt->root; Lt->root=Rt->root=NULL; bt->root=p;//最后把先建立的节点赋值给bt(我们就是通过bt传递的) } tree CreatHFMtree(int w[],int n)//传入两个参数,一个是数组w,一个是节点的数量n { tree zero,h[1000]; int i,k,k1,k2; tree *p; p=&zero; p->root=NULL; for (i=0;i<n;i++) Maketree(&h[i],w[i],p,p);//先建成n个树,再进行合并 for (k=n-1;k>0;k--)//n棵树合并,进行n-1次 { Fmin(h,&k1,&k2,k);//在已经建成的n棵树中,找出最小值的下标k1,次小值得下标k2,最小值每次只会在前k个值(每一次找出两个值都会在数组中忽略最小值) printf("%d %d\n",k1,k2); Maketree(&h[k1],h[k1].root->element+h[k2].root->element,&h[k1],&h[k2]);//这步可以说是哈夫曼树的核心代码,把找到的两个小值求和h[k1]+h[k2],作为h[k2]的树,而他的子树就是h[k1],h[k2] h[k2]=h[k];//每一次把最小值换成队尾的那个,此时最小值就没有了,而有了两个队尾元素,然后由于k--,队尾元素相当于被删除了一个,所以只剩下了除了最小数的全部元素(如果最小值就是队尾元素,那也是成立,可以自己思考一下) } return h[0]; } void Fmin(tree h[],int *k1,int *k2,int k)//k1是最小值的下标,k2是次小值的下标(这一部分其实就是维护由两个元素组成的堆) { int i,min1,min2; if (h[0].root->element<h[1].root->element) { *k1=0; *k2=1; min1=h[0].root->element; min2=h[1].root->element; } else { *k1=1; *k2=0; min1=h[1].root->element; min2=h[0].root->element; } for (i=2;i<=k;i++) if (h[i].root->element<min1)//如果比最小值还小 { *k2=*k1;//先更新次小值的为原来的最小值,原来的最小值更新为h[i].root->element *k1=i; min2=min1; min1=h[i].root->element; } else if (h[i].root->element<min2) { *k2=i; min2=h[i].root->element;//直接更新次小值 } } void PreOrd(node *t) { if (t) { printf("%d ",t->element); PreOrd(t->Lchild); PreOrd(t->Rchild); } } int main() { int w[1000]; int i,n; tree start; printf("请输入树节点的个数\n"); scanf("%d",&n); printf("请输入节点\n"); for (i=0;i<n;i++) scanf("%d",&w[i]); start=CreatHFMtree(w,n); PreOrd(start.root); printf("\n"); return 0; }
再来个算法竞赛入门经典中的例子