数据结构学习——Huffman树及其应用

来源:互联网 发布:飞狐淘宝客cms 编辑:程序博客网 时间:2024/04/29 08:12

Huffman树又叫最优树,是一类带权路径长度最短的树,有着广泛的应用。
1、 最优二叉树
从树中一个节点到另一个结点之间的分支构成这两个结点之间的路径,路径上的分支数目称做路径长度树的路径长度是从树根到每一个结点的路径长度之和。结点的带权路径长度为从该节点到树根之间的路径长度与节点上权的乘积,树的带权路径长度为树中所有叶子节点的带权路径长度之和,记作这里写图片描述
假设有n个权值这里写图片描述 ,试构造一棵有n个叶子节点的二叉树,每个叶子节点的带权为这里写图片描述 ,则其中带权路径长度WPL最小的二叉树称作最优二叉树或Huffman树。
例如,图1中3棵二叉树有4个叶子节点a、b、c、d,分别带权7、5、2、4,则他们带权路径长度分别为
这里写图片描述
其中(c)树最小。恰为Huffman树。
这里写图片描述
图1 具有不同带权路径长度的二叉树

那么,如何构造Huffman树呢?步骤如下:
(1) 将给定的n个权值 这里写图片描述构成一个二叉树集合,每个二叉树根节点分别带权 这里写图片描述,左右子树为空。
(2) 选择两个最小权值的二叉树分别作为左右子树构造一棵新的二叉树,新树的根节点权值为左右子树之和。
(3) 在二叉树集合中删除合并的两棵二叉树,添加新得到的二叉树。
(4) 重复步骤(2)(3)直到集合中只含一棵二叉树为止。
如图2所示,为Huffman树的构造过程。
这里写图片描述
图2 Huffman树的构造过程
2、 Huffman编码
利用二叉树来设计二进制的前缀编码(任一字符编码都不是另一个字符编码的前缀),假设每种字符在电文中出现的次数为 这里写图片描述,其编码长度为这里写图片描述 ,若电文有n中字符,则编码总长度为这里写图片描述 ,由前面得知,为使编码总长度最短,应以n中字符出现的频率为权重设计一棵Huffman树,由该树得到的编码即为Huffman编码。
Huffman编码具体做法:由于Huffman树中没有度为1的结点,则一棵有n个叶子节点的Huffman树共有2n-1个结点,可以存储在一个2n-1的数组中。由于构成Huffman树后,为求编码需从叶子节点出发到根,而为译码需从根出发的叶子节点,则对每个结点而言,既需知道双亲信息,又需知道孩子结点的信息。
Huffman编码的C程序:

typedef struct{    unsigned int weight;    unsigned int parent,lchild,rchild;}HNode,*huffmanTree;//动态分配数组存储Huffman树typedef char* HuffmanCode;//动态分配数组存储Huffman编码表//Huffman编码void HuffmanCoding(huffmanTree HT,HuffmanCode HC,int * w,int n){    //w存放n个字符的权值,构造Huffman数HT,并求出n个字符的Huffman编码HC    if (n<=1)    {        return;    }    int m=2*n-1;    HT=(huffmanTree)malloc((m+1)*sizeof(HNode));    for(int i=1;i<=n;i++)    {        HT[i].lchild=0;HT->rchild=0;        HT->parent=0;HT->weight=w[i];    }    for(;i<=m;i++)    {        HT[i].lchild=0;HT->rchild=0;        HT->parent=0;HT->weight=0;    }    //构建Huffman树    int min1,min2;    for(i=n+1;i<=m;i++)    {        SelectMinWeight(w,i-1,min1,min2);//在H[1...i-1]选择parent为0且weight最小的的结点,其序号分别为min1,min2        HT[min1].parent=i;HT[min2].parent=i;        HT[i].lchild=min1;HT[i].rchild=min2;        HT[i].weight=HT[min1].weight+HT[min2].weight;    }    //从叶子到根逆向求每个字符的Huffman编码    HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//分配n个字符编码的头指针向量    char* cd=(char*)malloc(n*sizeof(char));//分配求编码的工作空间    cd[n-1]='\0';    for(int i=1;i<=n;i++)//逐个字符求Huffman编码    {        int start=n-1;        for (int c=i,int 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]);    }    free(cd);}

参考文献:严蔚敏《数据结构》

0 0
原创粉丝点击