哈夫曼树的实现

哈夫曼树是一个很经典的问题,本文输入是一串数字,然后输出生成哈夫曼树的中序遍历结果

#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;

  }


再来个算法竞赛入门经典中的例子



哈夫曼树的实现_第1张图片


将建成的树左分岔设为0,右分叉设为1,可以得到书上的编码方式~~

你可能感兴趣的:(哈夫曼树的实现)