哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就叫作Huffman编码。
1951年,
哈夫曼和他在
MIT
信息论的同学需要选择是完成学期报告还是期末
考试。导师Robert M. Fano给他们的学期报告的题目是,寻找最有效的
二进制编码。由于无法证明哪个已有编码是最有效的,
哈夫曼放弃对已有编码的研究,转向新的探索,最终发现了基于有序频率
二叉树编码的想法,并很快证明了这个方法是最有效的。
由于这个算法,学生终于青出于蓝,超过了他那曾经和
信息论创立者
香农共同研究过类似编码的导师。
哈夫曼使用自底向上的方法构建
二叉树,避免了次优算法Shannon-Fano编码的最大弊端──自顶向下构建树
以哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。 在计算机信息处理中,“哈夫曼编码”是一种一致性编码法(又称“熵编码法”),用于数据的无损耗压缩。
/*
我要说明一下,下面代码不是我写的,代码出自清华大学朱老师作品,我贴出来学学,整理一下自己收藏的资料。
*/
#include <stdio.h>
#include <stdlib.h>
#define M 8
typedef struct node *link;
struct node { int f; link l, r; };
link NODE(int f, link l, link r)
{
link t = malloc(sizeof *t);
t->f = f; t->l = l; t->r = r;
return t;
}
link hh[M], *h = hh-1;
int N;
void swap(int i, int j)
{
link tmp = h[i]; h[i] = h[j]; h[j] = tmp;
}
void sift_down(int k, int n)
{
int j;
while (2*k<=n) {
j = 2*k;
if (j+1<=n && h[j+1]->f < h[j]->f) j++;
if (h[k]->f < h[j]->f) break;
swap(k, j); k = j;
}
}
void sift_up(int k)
{
int j;
while (k>1) {
j = k/2;
if (h[j]->f < h[k]->f) break;
swap(k, j); k = j;
}
}
link delMin()
{
swap(1, N--);
sift_down(1, N);
return h[N+1];
}
void insert(link t)
{
h[++N] = t;
sift_up(N);
}
void build_heap()
{
int i;
N = M;
for (i=N/2; i>=1; i--) sift_down(i, N);
}
link create_huffman_tree(int a[])
{
int i;
for (i=1; i<=M; i++) h[i] = NODE(a[i-1], NULL, NULL);
build_heap();
while (N>1) {
link t1 = delMin();
link t2 = delMin();
insert(NODE(t1->f + t2->f, t1, t2));
}
return delMin();
}
void pprint(link t)
{
if (t) {
printf("(");
printf("%d", t->f);
pprint(t->l);
pprint(t->r);
printf(")");
} else printf("()");
}
int main()
{
int a[] = { 5, 29, 7, 8, 14, 23, 3, 11 };
link root = create_huffman_tree(a);
printf("\\tree"); pprint(root); printf("\n");
return 0;
}