霍夫曼编码树的实现

转载:

http://hi.baidu.com/fire_man/blog/item/da1c192c9c2886ee8b1399ad.html

/* c6-7.h 赫夫曼树和赫夫曼编码的存储表示 */

typedef struct

{

    unsigned int weight;

    unsigned int parent,lchild,rchild;

}HTNode,*HuffmanTree; /* 动态分配数组存储赫夫曼树 */

typedef char **HuffmanCode; /* 动态分配数组存储赫夫曼编码表 */

 

/* algo6-1.c 求赫夫曼编码。实现算法6.12的程序 */

#include"c1.h"

#include"c6-7.h"

int min1(HuffmanTree t,int i)

{ /* 函数void select()调用 */

    int j,flag;

    unsigned int k=UINT_MAX; /* k为不小于可能的值 */

    for(j=1;j<=i;j++)

      if(t[j].weight<k&&t[j].parent==0)

        k=t[j].weight,flag=j;

    t[flag].parent=1;

    return flag;

}

void select(HuffmanTree t,int i,int *s1,int *s2)

{ /* s1为最小的两个值中序号小的那个 */

    int j;

    *s1=min1(t,i);

    *s2=min1(t,i);

    if(*s1>*s2)

    {

      j=*s1;

      *s1=*s2;

      *s2=j;

    }

}

void HuffmanCoding(HuffmanTree *HT,HuffmanCode *HC,int *w,int n) /* 算法6.12 */

{ /* w存放n个字符的权值(>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC */

    int m,i,s1,s2,start;

    unsigned c,f;

    HuffmanTree p;

    char *cd;

    if(n<=1)

      return;

    m=2*n-1;

    *HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); /* 0号单元未用 */

    for(p=*HT+1,i=1;i<=n;++i,++p,++w)

    {

      (*p).weight=*w;

      (*p).parent=0;

      (*p).lchild=0;

      (*p).rchild=0;

    }

    for(;i<=m;++i,++p)

      (*p).parent=0;

    for(i=n+1;i<=m;++i) /* 建赫夫曼树 */

    { /* HT[1~i-1]中选择parent0weight最小的两个结点,其序号分别为s1s2 */

      select(*HT,i-1,&s1,&s2);

      (*HT)[s1].parent=(*HT)[s2].parent=i;

      (*HT)[i].lchild=s1;

      (*HT)[i].rchild=s2;

      (*HT)[i].weight=(*HT)[s1].weight+(*HT)[s2].weight;

    }

    /* 从叶子到根逆向求每个字符的赫夫曼编码 */

    *HC=(HuffmanCode)malloc((n+1)*sizeof(char*));

    /* 分配n个字符编码的头指针向量([0]不用) */

    cd=(char*)malloc(n*sizeof(char)); /* 分配求编码的工作空间 */

    cd[n-1]='/0'; /* 编码结束符 */

    for(i=1;i<=n;i++)

    { /* 逐个字符求赫夫曼编码 */

      start=n-1; /* 编码结束符位置 */

      for(c=i,f=(*HT)[i].parent;f!=0;c=f,f=(*HT)[f].parent)

      /* 从叶子到根逆向求编码 */

        if((*HT)[f].lchild==c)

          cd[--start]='0';

        else

          cd[--start]='1';

      (*HC)[i]=(char*)malloc((n-start)*sizeof(char));

      /* 为第i个字符编码分配空间 */

      strcpy((*HC)[i],&cd[start]); /* cd复制编码()HC */

    }

    free(cd); /* 释放工作空间 */

}

void main()

{

    HuffmanTree HT;

    HuffmanCode HC;

    int *w,n,i;

    printf("请输入权值的个数(>1)");

    scanf("%d",&n);

    w=(int*)malloc(n*sizeof(int));

    printf("请依次输入%d个权值(整型)/n",n);

    for(i=0;i<=n-1;i++)

      scanf("%d",w+i);

    HuffmanCoding(&HT,&HC,w,n);

    for(i=1;i<=n;i++)

      puts(HC[i]);

}

 

 

/* algo6-2.cpp 实现算法6.13的程序,前半部分与algo6-1.cpp */

#include"c1.h"

#include"c6-7.h"

int min1(HuffmanTree t,int i)

{ /* 函数void select()调用 */

    int j,flag;

    unsigned int k=UINT_MAX; /* k为不小于可能的值 */

    for(j=1;j<=i;j++)

      if(t[j].weight<k&&t[j].parent==0)

        k=t[j].weight,flag=j;

    t[flag].parent=1;

    return flag;

}

void select(HuffmanTree t,int i,int *s1,int *s2)

{ /* s1为最小的两个值中序号小的那个 */

    int j;

    *s1=min1(t,i);

    *s2=min1(t,i);

    if(*s1>*s2)

    {

      j=*s1;

      *s1=*s2;

      *s2=j;

    }

} /* 以上同algo6-1.c */

void HuffmanCoding(HuffmanTree *HT,HuffmanCode *HC,int *w,int n) /* 前半部分为算法6.12 */

{ /* w存放n个字符的权值(>0),构造赫夫曼树HT,并求出n个字符的赫夫曼编码HC */

    int m,i,s1,s2; /* 此句与algo6-1.c不同 */

    unsigned c,cdlen; /* 此句与algo6-1.c不同 */

    HuffmanTree p;

    char *cd;

    if(n<=1)

      return;

    m=2*n-1;

    *HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); /* 0号单元未用 */

    for(p=*HT+1,i=1;i<=n;++i,++p,++w)

    {

      (*p).weight=*w;

      (*p).parent=0;

      (*p).lchild=0;

      (*p).rchild=0;

    }

    for(;i<=m;++i,++p)

      (*p).parent=0;

    for(i=n+1;i<=m;++i) /* 建赫夫曼树 */

    { /* HT[1~i-1]中选择parent0weight最小的两个结点,其序号分别为s1s2 */

      select(*HT,i-1,&s1,&s2);

      (*HT)[s1].parent=(*HT)[s2].parent=i;

      (*HT)[i].lchild=s1;

      (*HT)[i].rchild=s2;

      (*HT)[i].weight=(*HT)[s1].weight+(*HT)[s2].weight;

    }

    /* 以下为算法6.13,无栈非递归遍历赫夫曼树,求赫夫曼编码,以上同算法6.12 */

    *HC=(HuffmanCode)malloc((n+1)*sizeof(char*));

    /* 分配n个字符编码的头指针向量([0]不用) */

    cd=(char*)malloc(n*sizeof(char)); /* 分配求编码的工作空间 */

    c=m;

    cdlen=0;

    for(i=1;i<=m;++i)

      (*HT)[i].weight=0; /* 遍历赫夫曼树时用作结点状态标志 */

    while(c)

    {

      if((*HT)[c].weight==0)

      { /* 向左 */

        (*HT)[c].weight=1;

        if((*HT)[c].lchild!=0)

        {

          c=(*HT)[c].lchild;

          cd[cdlen++]='0';

        }

        else if((*HT)[c].rchild==0)

        { /* 登记叶子结点的字符的编码 */

          (*HC)[c]=(char *)malloc((cdlen+1)*sizeof(char));

          cd[cdlen]='/0';

          strcpy((*HC)[c],cd); /* 复制编码() */

        }

      }

      else if((*HT)[c].weight==1)

      { /* 向右 */

        (*HT)[c].weight=2;

        if((*HT)[c].rchild!=0)

        {

          c=(*HT)[c].rchild;

          cd[cdlen++]='1';

        }

      }

      else

      { /* HT[c].weight==2,退回 */

        (*HT)[c].weight=0;

        c=(*HT)[c].parent;

        --cdlen; /* 退到父结点,编码长度减1 */

      }

    }

    free(cd);

}

void main()

{ /* 主程序同algo6-1.c */

    HuffmanTree HT;

    HuffmanCode HC;

    int *w,n,i;

    printf("请输入权值的个数(>1)");

    scanf("%d",&n);

    w=(int *)malloc(n*sizeof(int));

    printf("请依次输入%d个权值(整型)/n",n);

    for(i=0;i<=n-1;i++)

      scanf("%d",w+i);

    HuffmanCoding(&HT,&HC,w,n);

    for(i=1;i<=n;i++)

      puts(HC[i]);

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
霍夫曼树是一种特殊的二叉,它的构造过程是,对于给定的 n 个权值,构造 n 个节点的二叉,每个节点的权值为对应权值,然后将这些节点按照权值从小到大排序,每次取出权值最小的两个节点作为左右子节点构造一个新的节点,其权值为左右子节点权值之和,再将这个新节点插入到原来的节点序列中,重复以上步骤直到只剩下一个节点,这个节点就是霍夫曼树的根节点。 霍夫曼编码是一种变长编码,它将出现频率较高的字符用较短的编码,出现频率较低的字符用较长的编码,从而达到压缩数据的目的。霍夫曼编码的构造过程是,在霍夫曼树上从根节点到叶子节点的路径上,左边表示 0,右边表示 1,叶子节点的编码即为该字符的霍夫曼编码。 下面是 Python 代码实现: ```python from queue import PriorityQueue class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def __lt__(self, other): return self.val < other.val def buildHuffmanTree(weights): heap = PriorityQueue() for weight in weights: heap.put(TreeNode(weight)) while heap.qsize() > 1: left = heap.get() right = heap.get() new_node = TreeNode(left.val + right.val, left, right) heap.put(new_node) return heap.get() def buildHuffmanCode(root): code = {} def dfs(node, path): if not node.left and not node.right: # 叶子节点 code[node.val] = path return dfs(node.left, path+'0') dfs(node.right, path+'1') dfs(root, '') return code weights = [5, 2, 7, 9, 4, 3] root = buildHuffmanTree(weights) code = buildHuffmanCode(root) print(code) ``` 输出结果为: ``` {2: '000', 3: '0010', 4: '0011', 5: '01', 7: '10', 9: '11'} ``` 可以看到,霍夫曼编码的结果为一个字典,键为字符的 ASCII 码,值为对应的霍夫曼编码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值