算法学习-哈夫曼编码(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了啊。

既然这么好,下面附上代码实现。

代码实现

//
//  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, *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] = {*w, 0, 0, 0};
    }
    for (; i <= m; i++) {
        HT[i] = {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));

        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;
}
时间: 2024-08-07 21:18:06

算法学习-哈夫曼编码(c++实现)的相关文章

贪心算法应用-哈夫曼编码

哈夫曼编码应用于数据文件和图像压缩的编码方式.其压缩率通常在20%~90%之间.在进行远距离通信时,通常需要把将要传送的文字转换为由二进制字符组成的字符串,并使要传送的电文总长度尽可能的短.显然只要将点文章出现次数多的字符采用尽可能短的编码,就可以减少要传送的电文总长度. 哈夫曼编码的核心思想: (1)每一个字符用一个0,1串作为其代码,并要求任意一个字符的代码都不是其他字符代码的前缀. (2)用字符在文件中出现的频率来建立一个用0,1串表示各字符的最优表示方式,即使出现频率高的字符获得较短编码

一步两步学算法之哈夫曼编码(最优二叉树)

比较难理解的 都打了备注了 1 #include "stdio.h" 2 #include "stdlib.h" 3 #include "string.h" 4 char alphabet[]={'A','B','C','D'}; 5 typedef struct 6 { 7 int weight; //权值 8 int parent; //父节点序号 9 int left ; 10 int right; 11 }HuffmanTree; 12

基于哈夫曼编码的文件压缩(c++版)

本博客由Rcchio原创 我了解到很多压缩文件的程序是基于哈夫曼编码来实现的,所以产生了自己用哈夫曼编码写一个压缩软件的想法,经过查阅资料和自己的思考,我用c++语言写出了该程序,并通过这篇文章来记录一下自己写该程序学到的东西.因为本人写的程序在压缩率上,还有提升的空间,所以本文将不定期更新,但程序整体的思路不会有较大的改动. 一.基于哈夫曼编码可实现压缩文件的原理分析 在计算机中,数据的存储都是二进制的,并且以字节作为基本的存储单位,像英文字母在文本中占一个字节,汉字占两个字节,我们把这种每一

贪心算法-霍夫曼编码

霍夫曼编码是一种无损数据压缩算法.在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度.期望值降低,从而达到无损压缩数据的目的.例如,在英文中,e的出现机率最高,而z的出现概率则最低.当利用霍夫曼编码对一篇英文进行压缩时,e极有可能用一个比特来表示,而z则可能花去25个比特(不是26).用普通的表示方法时,每个

信源编码算法(费诺编码&amp;&amp;哈夫曼编码)

信源编码算法 费诺编码 Fano coding 哈夫曼编码 Huffman coding 费诺编码 编码步骤 将信源符号按照其概率大小,从大到小排列: 将这一组信源符号分成概率之和尽可能接近或者相等的一组(即两组分别的概率和之间的差尽可能小!): 将上面一组符号编码成0,下面一组编码成1,反之亦可: 将已经分好的组重复步骤2,3,直到不能再进行分组为止: 从左到右一次写出码字. 费诺编码演示 已知: 编码过程为: 哈夫曼编码 Huffman coding 编码步骤 将信源符号按照概率大小从大到小

【算法总结】哈夫曼树和哈夫曼编码

一.哈夫曼树 1. 哈夫曼树也称最优二叉树. 叶子节点的权值是对叶子节点赋予的一个有意义的数值量. 设二叉树具有 n 个带权值的叶子结点,从根节点到各个叶子结点的路径长度与相应叶子结点权值的乘积之和叫做二叉树的带权路径长度. 给定一组具有确定权值的叶子结点,可以构造处不同的二叉树,将其中带权路径长度最小的二叉树称为哈夫曼树. 2. 基本思想: 初始化:由给定的 n 个权值 $\left\{ \omega_{1},\omega_{2},\cdots ,\omega_{n}\right\}$构造 n

【数据结构与算法】二叉树——哈夫曼编码

最近有很多的小朋友问我什么是哈夫曼编码,哈夫曼编码是一种可变字长的编码,那什么是可变字长呢?就是一句话里的每一个字符(ASCII码)它的位数(长度)是不一样的.就像我们一句话(AAAACCCCCDDDDBBE)有A,B,C,D,E五种字符,在这里我们可以用01表示A字符,用001表示B字符,用11表示C字符,用10表示D字符,用000表示E字符.如下图: 既然知道了哈夫曼编码是什么了,那又有好奇的小朋友又会问了:那么哈夫曼编码是按照什么原理生成的呢? 在这里我就要告诉大家,哈夫曼编码是根据哈夫曼

C语言之霍夫曼编码学习

?1,霍夫曼编码描述哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩. 在计算机信息处理中,"哈夫曼编码"是一种一致性编码法(又称"熵编码法"),用于数据的无损耗压缩.这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码.这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目

霍夫曼编码/译码器

赫夫曼树的应用 1.哈夫曼编码 在数据通信中,需要将传送的文字转换成二进制的字符串,用0,1码的不同排列来表示字符.例如,需传送的报文为"AFTER DATA EAR ARE ART AREA",这里用到的字符集为"A,E,R,T,F,D",各字母出现的次数为{8,4,5,3,1,1}.现要求为这些字母设计编码.要区别6个字母,最简单的二进制编码方式是等长编码,固定采用3位二进制,可分别用000.001.010.011.100.101对"A,E,R,T,F