回 帖 发 新 帖 刷新版面

主题:[原创]赫夫曼编码实现 (ANSI C)

欢迎拍砖,提出不足之处,我好提高 hoho

下面贴出我写的求赫夫曼编码的实现,是个头文件:

#ifndef _HuffmanTree_h
#define _HuffmanTree_h

/*----------------------------------------------------------------*/
/* HuffmanTree CreateHuffmanTree(WEIGHT w[], int n)  创建赫夫曼树 */
/* void DestroyHuffmanTree(HuffmanTree HT)           摧毁赫夫曼树 */
/* HuffmanCode GetHuffmanCode(HuffmanTree HT)     获得赫夫曼编码  */
/* void DestroyHuffmanCode(HuffmanCode HC)        摧毁赫夫曼编码  */
/*----------------------------------------------------------------*/

/*-----------------------示范例程开始-------------------------------
#include <stdio.h>
#include <stdlib.h>
#include "HuffmanTree.h"

int main(int argc, char *argv[])
{
     int w[8] = {5, 29, 7, 8, 14, 23, 3, 11};
     int i;
     HuffmanTree tree = CreateHuffmanTree(w, 8);
     HuffmanCode code = GetHuffmanCode(tree);

     for (i=0; i < 8; ++i)
     {
          printf("%d\t%s\n", w[i], code[i]);
     }

     system("pause");
     DestroyHuffmanTree(tree);
     DestroyHuffmanCode(code);
     return 0;
}
-------------------------示范例程结束-----------------------------*/

#include <stdlib.h>

typedef unsigned int WEIGHT;  //权
#define WEIGHT_0    ( 0 )     //空权
#define HTP_NULL    ( -1 )    //赫夫曼树结点接地标志

typedef struct _HuffmanTreeNode    //定义赫夫曼树节点
{
     int parent;
     int lchild;
     int rchild;
     WEIGHT weight;
} HuffmanTreeNode;
typedef struct _HuffmanTree
{
     HuffmanTreeNode* nodes;  //树节点数组
     int how_many_leaves;     //叶子数
}* HuffmanTree;

typedef char** HuffmanCode;

void SelectTwoMinNodes(int two_min[2], HuffmanTreeNode nodes[],int n);
//选择nodes中无parent且weight最小的两个节点的编号到min

HuffmanTree CreateHuffmanTree(WEIGHT w[], int n)
{//创建赫夫曼树,其权值信息在数组w[n]中
     HuffmanTree HT = NULL;
     int two_min_nodes[2];    //权最小的两个节点,[0]最小,[1]第二小
     int how_many_nodes;
     int i;

     if (n < 2)
     {
          return NULL;
     }
     HT = (HuffmanTree)malloc(sizeof(struct _HuffmanTree));
     //内存溢出处理省略
     HT->how_many_leaves = n;
     how_many_nodes = n + n - 1;
     HT->nodes = (HuffmanTreeNode *)malloc
                 (how_many_nodes * sizeof(struct _HuffmanTreeNode));
     //内存溢出处理省略

     for (i=0; i < n; ++i)    //初始化前n个节点
     {
          HT->nodes[i].weight = w[i];
          HT->nodes[i].parent = HTP_NULL;
          HT->nodes[i].lchild = HTP_NULL;
          HT->nodes[i].rchild = HTP_NULL;
     }
     for (i=n; i < how_many_nodes; ++i)  //初始化剩下的节点
     {
          HT->nodes[i].weight = WEIGHT_0;
          HT->nodes[i].parent = HTP_NULL;
          HT->nodes[i].lchild = HTP_NULL;
          HT->nodes[i].rchild = HTP_NULL;
     }
     for (i=n; i < how_many_nodes; ++i)  //建立赫夫曼树
     {
          SelectTwoMinNodes(two_min_nodes, HT->nodes, i);
          HT->nodes[ two_min_nodes[0] ].parent = i;
          HT->nodes[ two_min_nodes[1] ].parent = i;
          HT->nodes[i].lchild = two_min_nodes[0];
          HT->nodes[i].rchild = two_min_nodes[1];
          HT->nodes[i].weight =
                    HT->nodes[ two_min_nodes[0] ].weight
                    + HT->nodes[ two_min_nodes[1] ].weight;
     }
     return HT;
}

void DestroyHuffmanTree(HuffmanTree HT)
{//摧毁赫夫曼树
     free(HT->nodes);
     free(HT);
}

void SelectTwoMinNodes(int min[2], HuffmanTreeNode nodes[], int n)
{//选择nodes中无parent且weight最小的两个节点的编号到min
     int i;
     WEIGHT min_weight;

     //1.找到最小的
     min[0] = 0;
     min_weight = 0;
     for (i=0; i < n; ++i)
     {
          if ( (HTP_NULL == nodes[i].parent)
                 && ((0 == min_weight)
                    ||(nodes[i].weight < min_weight)) )
          {
               min[0] = i;
               min_weight = nodes[i].weight;
          }
     }

     //2.找到第二小的
     min[1] = 0;
     min_weight = 0;
     for (i=0; i < n; ++i)
     {
          if ((i != min[0])
                 && (HTP_NULL == nodes[i].parent)
                 && ((0 == min_weight)
                    ||(nodes[i].weight < min_weight)))
          {
               min[1] = i;
               min_weight = nodes[i].weight;
          }
     }
     return;
}

HuffmanCode GetHuffmanCode(HuffmanTree HT)
{//求赫夫曼树HT对应的赫夫曼编码
     HuffmanCode code = NULL;
     char *temp = NULL;
     int n;
     int start;
     int parent, child;
     int i,j;

     n = HT->how_many_leaves;
     code = (HuffmanCode)malloc((n + 1) * sizeof(char *));
     temp = (char *)malloc((n + 1) * sizeof(char));  //内存溢出错误处理省略
     temp[n] = '\0';
     for (i=0; i < n; ++i)
     {
          start = n;
          child = i;
          parent = HT->nodes[child].parent;
          while ( HTP_NULL != parent )
          {
               temp[--start] = HT->nodes[parent].lchild == child ? '0' : '1';
               child = parent;
               parent = HT->nodes[child].parent;
          }
          code[i] = (char *)malloc((n - start + 1) * sizeof(char));
          for (j=0; '\0' != temp[start+j]; ++j)   //将temp复制到code[i]
          {
               code[i][j] = temp[start+j];
          }
          code[i][j] = '\0';
     }
     code[n] = NULL;     //做结尾标记
     free(temp);
     return code;
}

void DestroyHuffmanCode(HuffmanCode HC)
{//摧毁赫夫曼编码
     int i = 0;

     while (NULL != HC[i])
     {
          free(HC[i++]);
     }
     free(HC);
}

#endif


 

回复列表 (共2个回复)

沙发

另一种从赫夫曼树求赫夫曼编码的实现:

HuffmanCode GetHuffmanCode2(HuffmanTree HT)
{//求赫夫曼树HT对应的赫夫曼编码
     HuffmanCode code = NULL;
     enum _flag{LEFT, RIGHT, END}* flag = NULL;
     char *temp = NULL;
     int n;
     int len;
     int p;
     int i;

     n = HT->how_many_leaves;
     len = 0;
     p = n + n - 2;
     code = (HuffmanCode)malloc((n + 1) * sizeof(char *));
     flag = (enum _flag *)malloc((p + 1) * sizeof(enum _flag));
     temp = (char *)malloc((n + 1) * sizeof(char));  //内存溢出错误处理省略
     for (i=0; i <=p ; ++i)
     {
          flag[i] = LEFT;
     }
     while (HTP_NULL != p)
     {
          if (LEFT == flag[p])
          {
               flag[p] = RIGHT;
               if (HTP_NULL != HT->nodes[p].lchild)
               {
                    p = HT->nodes[p].lchild;
                    temp[len++] = '0';
               }
               else if (HTP_NULL == HT->nodes[p].rchild)
               {
                    //temp[len] = '\0';
                    code[p] = (char *)malloc((len + 1) * sizeof(char));
                    for (i=0; i < len; ++i)   //将temp复制到code[p]
                    {
                         code[p][i] = temp[i];
                    }
                    code[p][i] = '\0';
               }
          }
          else if (RIGHT == flag[p])
          {
               flag[p] = END;
               if (HTP_NULL != HT->nodes[p].rchild)
               {
                    p = HT->nodes[p].rchild;
                    temp[len++] = '1';
               }
          }
          else
          {
               flag[p] = LEFT;
               p = HT->nodes[p].parent;
               --len;
          }
     }

     code[n] = NULL;     //做结尾标记
     free(temp);
     free(flag);
     return code;
}

板凳

支持~~那段选择最小元素的部分可以用堆数据结构改进~~这帖就算不加精也链接起来准备

我来回复

您尚未登录,请登录后再回复。点此登录或注册