算法学习-哈夫曼编码(c++实现)

哈夫曼编码

哈夫曼编码虽然简单,但是是一个非常重要的编码方式,它解决了数据存储的一个非常重要的问题:压缩!它的编码方式是最优的,无损的,尤其在图像中使用的非常多。下面讲下它的原理。

编码方式

哈夫曼编码的构造是依据权值的大小来实现的。首先根据权值构造哈夫曼树,然后对哈夫曼树进行逆向遍历,从而找到每个节点的编码方式。

例如:
abbcccdddde这个是一个字符串,一共有5个字符。每个字符的权值就是出现的频率,那么a就是1b权值为2c的权值为3d的权值为4e的权值为1。在普通的编码方式中,表示5个字母最少要3位,也就是3bit.那么这串字符就需要1*3+2*3+3*3+4*3+1*3=33 bits。而使用哈夫曼的编码呢?

构造哈夫曼树的流程是每次找到权值最小的两个,放到一起,组成一颗树,根节点是权值的和。
第一步:

       2  
      / \
     1   1

这样权值为1的ae就已经构造完了。并且把当前的2放回权值列表,下面最小的两个是这个2b的权值2

           4
         /   \
        2     2
       /  \
      1    1

这样第二步就构造完了,再把4放回权值列表,继续找,依次类推

      ...省略ing

结果的哈夫曼树: 

                     11
                  /       \
                 7         4  
               /  \       / \  
              3    4     2   2
                        / \
                       1   1

好,这就是最终的哈夫曼树。看见没有~ 每个叶子节点,都代表了一个字符,1就是ae的。2b的,依次...省略ing

然后遍历,左就是0,右就是1
c的就是00d的就是01,a的是100,b=11,e=101.这样就成功了。

下面验证成果:计算存储空间。从ae:3*1+2*2+2*3+2*4+3*1 = 24 bits。发现没,少了整整9 bits,什么概念?也就是说压缩了接近1/3啊,假如3G大小,压缩后就是2G了啊。
既然这么好,下面附上代码实现。

代码实现

<pre name="code" class="cpp">//
//  main.cpp
//  HuffmanCode
//
//  Created by Alps on 14/11/22.
//  Copyright (c) 2014年 chen. All rights reserved.
//

#include <iostream>
using namespace std;
typedef struct HTNode{
    int weight;
    int parent;
    int lchild;
    int rchild;
    HTNode(int w, int p, int l, int r):weight(w),parent(p),lchild(l),rchild(r){}
}HTNode, *HuffmanTree;
typedef char** HuffmanCode;

void Select(HuffmanTree HT, int num, int &child1, int &child2);

void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n){
    //
    int m,i;
    int child1,child2;
    if (n <= 1) {
        return;
    }
    m = n*2-1;//整棵树的节点数
    HT = (HuffmanTree)malloc((m+1) * sizeof(HTNode));//申请足够空间
    for (i = 1; i <= n; i++,w++) {
        HT[i] = HTNode(*w, 0, 0, 0);
    }
    for (; i <= m; i++) {
        HT[i] = HTNode(0, 0, 0, 0);
    }
    for (i = n+1; i <= m; i++) {
        Select(HT,i-1,child1,child2);
        HT[child1].parent = i;
        HT[child2].parent = i;
        HT[i].lchild = child1;
        HT[i].rchild = child2;
        HT[i].weight = HT[child1].weight + HT[child2].weight;
        printf("%d==%d\n",child1,child2);
    }
    
    HC = (char**)malloc((n+1)*sizeof(char *));
    
    char *cd = (char*)malloc(n*sizeof(char));
//    memset(cd, '\0', n*sizeof(char));
    int c = 0;
    
    int tempParent,count;
    for (i = 1; i <= n; i++) {
        count = 0;
        for (c = i,tempParent = HT[i].parent; tempParent != 0;c=tempParent, tempParent = HT[tempParent].parent) {
            if (HT[tempParent].lchild == c) {
                cd[count++] = '0';
            }else{
                cd[count++] = '1';
            }
        }
        cd[count]='\0';
        printf("%s~%d\n",cd,i);
        HC[i] = (char *)malloc((count)*sizeof(char));
        for (int j = count; j>=0; j--) {
            HC[i][count-j] = cd[j-1];
        }
//        strcpy(HC[i], cd);
//        memset(cd,'\0', n*sizeof(char));//error
    }
}

void Select(HuffmanTree HT, int num, int &child1, int &child2){
    child1 = 0;
    child2 = 0;
    int w1 = 0;
    int w2 = 0;
    for (int i = 1; i <= num; i++) {
        if (HT[i].parent == 0) {
            if (child1 == 0) {
                child1 = i;
                w1 = HT[i].weight;
                continue;
            }
            if (child2 == 0) {
                child2 = i;
                w2 = HT[i].weight;
                continue;
            }
            if (w1 > w2 && w1 > HT[i].weight) {
                w1 = HT[i].weight;
                child1 = i;
                continue;
            }
            if (w2 > w1 && w2 > HT[i].weight) {
                w2 = HT[i].weight;
                child2 = i;
                continue;
            }
        }
    }
}






int main(int argc, const char * argv[]) {
    char a[] = "abcaab";
    int i = (int)strlen(a);
    printf("%d\n",i);
    
    int b[]={1,2,3,4};
    HuffmanTree HT;
    HuffmanCode HC;
    HuffmanCoding(HT, HC, b, 4);
    for (i = 1; i <= 7; i++) {
        printf("%d-%d\n",HT[i].weight,HT[i].parent);
    }
    for (i = 1; i <=4; i++) {
        printf("%s\n",HC[i]);
    }
    return 0;
}

 


 


  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值