2007-08-23

    链式存储结构构造哈夫曼树的实现 - [Algorithms]

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://conoon.blogbus.com/logs/7872503.html

    该实例是一个链式存储结构构造哈夫曼树的实现的例子。
    #include "stdio.h"
    #include "stdlib.h"
    #include "conio.h"

    #define LEN sizeof(HFtree) /*HFtree结构体大小*/

    /*哈夫曼树结构体*/
    typedef struct tagHFtree
    {
     char data;            /*结点数据,以后用到*/
     double weight;         /*结点的权重*/
     struct tagHFtree* parent; /*双亲结点*/
     struct tagHFtree* lchild; /*左孩子*/
     struct tagHFtree* rchild; /*右孩子*/
     struct tagHFtree* next;    /*指向下一个结点*/
    }HFtree;

    /*哈夫曼编码结构体*/
    struct tagHFcode
    {
     char data;           /*结点数据*/
     double weight;       /*结点的权重*/     
     int code[20];            /*存放编码*/
     int top;             /*编码的位数*/
    };

    /***********************************************
     创建哈夫曼树核心部分
    ************************************************/
    void Create(HFtree**head)
    {
     HFtree*lp,*temp,*lchild,*rchild;
     while((*head)->next->next!=NULL)
     {
      lchild=rchild=(*head);   /*每次从头开始查找,这里(*head)的weight没用,*/
                                              /*刚好用来放左右孩子*/           
      temp=(*head)->next;    /*最初的的weight*/
      lchild->weight=rchild->weight=3.14e+38;  /*重新找时每次将左右孩子的weight置为最大*/
      lp=(HFtree*)malloc(LEN);
                    lp->parent=NULL;
      while(temp!=NULL)            /*查找最小的作为左孩子*/
      {
       if(lchild->weight > temp->weight)
       {
        lchild=temp;
       }
       temp=temp->next;
      }
      temp=(*head)->next;          /*重新定位到(*head)->next*/
      while(temp!=NULL)            /*查找次小的作为右孩子*/
      {                 /*注意这里不要用temp->weight!=lchild->weigh*/
       if(rchild->weight > temp->weight && temp!=lchild) 
       {
        rchild=temp;
       }
       temp=temp->next;
      }
      
      lp->lchild=lchild;                        /*对LP及其左右孩子附值*/
      lp->rchild=rchild;                        
      lchild->parent = rchild->parent =lp;
      lp->weight=lchild->weight + rchild->weight;  /*将左右孩子的权值相加*/
      lp->next=(*head)->next;                /*将LP插到表头*/
      (*head)->next=lp;                      /*每次让(*head)->next指向新加进来的结点*/
      temp=lp;                               /*将lp和temp两个指针重新定位,用来遍历链表*/
      lp=lp->next;
      while(lp!=NULL)                        /*将左右孩子从待创建的链表系列中删除*/
      {
       if(lp==lchild || lp==rchild)
       {
        temp->next=lp->next;
        lp->next=NULL;
       }
       else
        temp=lp;
       lp=temp->next;
       
      }
     }
    }


    /***********************************************
    创建哈夫曼树
    ************************************************/
    void CreateHFtree(double nodewei[],int n,HFtree**head)
    {
     int i=0;
     HFtree*lp=(HFtree*)malloc(LEN),*rear;
     (*head)=(HFtree*)malloc(LEN);
            (*head)->parent=NULL;
     (*head)->next=rear=lp;                                 /*head头结点,保证指向剩余的结点链*/
     lp->parent=lp->lchild=lp->rchild=lp->next=NULL;
     while(iweight=nodewei[i++];
      rear->next=lp;                          /*第一次REAR指向自身*/
      rear=lp;
      lp=(HFtree*)malloc(LEN);
      lp->parent=lp->lchild=lp->rchild=lp->next=NULL;
     }
     free(lp);                                    /*释放最后一个结点*/
     Create(head);                               /*创建一棵树,树的头结点为(*HEAD)->next*/
    }

    /*************************************************
     由先序遍历求出哈夫曼树求出哈夫曼编码
    **************************************************/
    void HFcoding(HFtree*root,HFtree*temp,struct tagHFcode HFcode[],int*leaftop)
    {
     if(root!=NULL)
     {
      if(root->lchild==NULL && root->rchild==NULL)    /*是叶子结点,求得编码*/
      {
       temp=root;
       HFcode[(*leaftop)].top=0;
       HFcode[(*leaftop)].weight=root->weight;
       HFcode[(*leaftop)].data=root->data;
       while(temp->parent!=NULL)
       {
        if(temp->parent->lchild==temp)                   
        HFcode[(*leaftop)].code[HFcode[(*leaftop)].top]=0;
        else
        HFcode[(*leaftop)].code[HFcode[(*leaftop)].top]=1;
        HFcode[(*leaftop)].top++;
        temp=temp->parent;
       }
       (*leaftop)++;
      }
      HFcoding(root->lchild,temp,HFcode,leaftop);
      HFcoding(root->rchild,temp,HFcode,leaftop);
    }
    }

    /***********************************************
     输出求得的哈夫曼编码
    ************************************************/
    void OutCoding(struct tagHFcode HFcode[],int leaftop)
    {
     int i=0,j=0;          for(;i<leaftop;i++)          {                 printf("%.1f :",HFcode[i].weight);                 j=HFcode[i].top-1;                 while(j>=0 )                 {                  printf("%d",HFcode[i].code[j]);                  j--;                 }                 printf("\n");          }
    }
    /********************************************
    用括号表示法输出树
    **********************************************/
    void OutTree(HFtree *root)
    {
     if(root != NULL)
     {
      printf("%.1f",root->weight);       /*先输出根结点*/
      if(root->lchild != NULL || root->rchild != NULL)
      {
       printf("(");
       OutTree(root->lchild);        /*处理左子树*/
       if(root->rchild != NULL)
       {
        printf(",");
       }
       OutTree(root->rchild);         /*处理右子树*/
       printf(")");
      }
     }
    }

    /*****************************************************************
     用树形表示法输出树
    ******************************************************************/
    void DispTree(HFtree *root,int x,int y,int n)     /*n用来控制第一层树的高度*/
    {
     int i=0;
     if(root !=NULL)
      {
        gotoxy(x,y);                               /*到相应结点输出*/
        printf("%.1f",root->weight);
        if(root->lchild != NULL)                  /*处理左子树,这里只有第一次N为可变的,*/
        {
           i=1;                                   /*为的是能够输出整棵树,而不会被覆盖,*/
           while(ilchild,x-n,y+n,2);       /*递归处理左子树*/
         }
         if(root->rchild != NULL)
        {
           i=1;
           while(irchild,x+n,y+n,2);       /*递归处理右子树*/
         }
       }
    }
     
    /*****************************************************************
     主函数入口
    ******************************************************************/
    void main()
    {
            double nodewei[20];
            struct tagHFcode HFcode[20];
            int leaftop=0,i=0;
            HFtree*temp=NULL;
            HFtree*head;
            textbackground(1);
            textcolor(2);
            clrscr();
            printf("the HFtree and HFcoding demo\r\n");
            printf("Input the leafnode weight:");
            scanf("%lf",&nodewei[i]);
            while(nodewei[i++]!=0.0)/*接收数据,以0结尾*/
            scanf("%lf",&nodewei[i]);
            CreateHFtree(nodewei,i-1,&head);  /*根据接收的数据创建*/
            printf("HFtree:");
            OutTree(head->next);              /*输出哈夫曼树括号表示法*/
            HFcoding(head->next,temp,HFcode,&leaftop);  /*根据哈夫曼树,求出哈夫曼编码*/
            printf("\nthe HFcoding is:\n");
            OutCoding(HFcode,leaftop);        /*输出哈夫曼编码*/
            DispTree(head->next,30,10,6);     /*用树形表示法输出树*/
            getch();
    }


    收藏到:Del.icio.us




    Tag:
    引用地址:

发表评论

您将收到博主的回复邮件
记住我