哈夫曼编码(最优前缀码)

        作为哈夫曼树的一个重要应用,我们来介绍哈夫曼编码。在我的上一篇博文《树之哈夫曼树》中已经介绍了建立哈夫曼树的过程,而由哈夫曼树求得的编码为最优前缀码。每个叶子表示的字符的编码,就是从根到叶子的路径上的标号依次相连所形成的编码,显然这就是该字符的最优前缀码。所谓前缀码是指,对字符集进行编码时,要求字符集中任一字符的编码都不是其它字符的编码的前缀,比如常见的等长编码就是前缀码。所谓最优前缀码是指,平均码长或文件总长最小的前缀编码称为最优的前缀码(这里的平均码长相当于码长的期望值)。

        我们知道,变长编码可能使解码产生二义性,而前缀码的出现很好地解决了这个问题。而平均码长相当于二叉树的加权路径长度,从这个意义上说,由哈夫曼树生成的编码一定是最优前缀码,故通常不加区分的将哈夫曼编码也称作最优前缀码。

        需要注意的是,由于哈夫曼树建立过程的不唯一性可知,生成的哈夫曼编码也是不唯一的,并且在本文中,将树中左分支和右分支分别标记为0和1也造成了哈夫曼编码的不唯一性(当然也可以反过来,将左分支记为1,右分支记为0)。

        在实际应用中,我们通常采用下列做法:根据各个字符的权值建立一颗哈夫曼树,求得每个字符的哈夫曼编码,有了每个字符的哈夫曼编码,我们就可以制作一个该字符集的哈夫曼编码表。有了字符集的哈夫曼编码表之后,对数据文件的编码过程是:依次读人文件中的字符c,在哈夫曼编码表H中找到此字符,将字符c转换为对应的哈夫曼编码串。对压缩后的数据文件进行解码则必须借助于哈夫曼树,其过程是:依次读人文件的二进制码,从哈夫曼树的根结点出发,若当前读入0,则走向左孩子,否则走向右孩子。一旦到达某一叶子时便译出相应的字符。然后重新从根出发继续译码,直至文件结束。下面给出制作哈夫曼编码表的过程的代码,通过以上的分析,读者不难写出文件编码过程和解码过程的代码。

#include
#include
#include
#include
using namespace std;

#define n 6           //叶子数目
#define m 2*n-1       //树中结点总数
typedef struct{       //结点类型
    double weight;    //结点的权值
    int parent,lchild,rchild;//双亲指针及左右孩子
}HTNode;
typedef HTNode HuffmanTree[m];//HuffmanTree是向量类型

typedef struct{       //用于SelectMin函数中排序的结点类型
    int id;           //保存根结点在向量中的序号
    double weight;    //保存根结点的权值
}temp;

typedef struct{       //编码结点
    char ch;          //存储字符
    char bits[n+1];   //存放编码位串
}CodeNode;
typedef CodeNode HuffmanCode[n];

void InitHuffmanTree(HuffmanTree T){
    //初始化哈夫曼树
    //将2n-1个结点里的三个指针均置为空(即置为-1),权值置为0
    for(int i=0;i=0){//直至上溯到T[c]是树根为止
            //若T[c]是T[p]的左孩子,则生成代码0;否则生成代码1
            if(T[p].lchild==c)
                cd[--start]='0';
            else
                cd[--start]='1';
            c=p;//继续上溯
        }
        strcpy(H[i].bits,&cd[start]);//复制编码位串
    }
}

//*************************测试函数**********************************
int main(){
    HuffmanTree T;
    HuffmanCode H;
    printf("请输入%d个叶子结点的权值来建立哈夫曼树:\n",n);
    CreateHuffmanTree(T);
    printf("请输入%d个叶子结点所代表的字符:\n",n);
    CharSetHuffmanEncoding(T,H);
    printf("哈夫曼树已经建好,哈夫曼编码已经完成,输出如下:\n");
    printf("哈夫曼树:\n");
    for(int i=0;i

测试样例及预测运行结果:(表中和图中的权重数值weight均需要乘以0.01)

哈夫曼编码(最优前缀码)_第1张图片

哈夫曼编码(最优前缀码)_第2张图片

运行结果:

哈夫曼编码(最优前缀码)_第3张图片


你可能感兴趣的:(算法)