数据结构实验之二叉树六:哈夫曼编码
Time Limit: 1000 ms Memory Limit: 65536 KiB
Problem Description
字符的编码方式有多种,除了大家熟悉的ASCII编码,哈夫曼编码(Huffman Coding)也是一种编码方式,它是可变字长编码。该方法完全依据字符出现概率来构造出平均长度最短的编码,称之为最优编码。哈夫曼编码常被用于数据文件压缩中,其压缩率通常在20%~90%之间。你的任务是对从键盘输入的一个字符串求出它的ASCII编码长度和哈夫曼编码长度的比值。
Input
输入数据有多组,每组数据一行,表示要编码的字符串。
Output
对应字符的ASCII编码长度la,huffman编码长度lh和la/lh的值(保留一位小数),数据之间以空格间隔。
Sample Input
AAAAABCD
THE_CAT_IN_THE_HAT
Sample Output
64 13 4.9
144 51 2.8
Hint
Source
xam
每个字符ASCII码是占8个字节的。所以长度就是字符数×8;
哈夫曼编码:实质上就是一个求最优二叉树的问题,就是求每个字母出现的次数,从小到大排序,存入队列,然后由两个最小值想加,相加的数取代两个最小值,然后循环此过程。此算法容易超时。
例如 每个字符出现的长度 1 3 1 4 5
第一次出来2, 队列变成3 4 5 2;
第二次出来5,队列变成4 5 5;
第三次出来9,队列变成5 9;
第四次出来14,队列变成14;
所以哈夫曼编码长度就是2 + 5 + 9 + 14 = 30;
纯c代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> void qs(int st[], int l, int r) { int x = st[l]; int i = l, j = r; if(i >= j) return; while(i < j) { while(i < j && st[j] >= x) j--; st[i] = st[j]; while(i < j && st[i] <= x) i++; st[j] = st[i]; } st[i] = x; qs(st, l, i - 1); qs(st, i + 1, r); } int main() { int l, i, sum1, sum2; int t[1000]; char s[1000]; int q[1000]; while(~scanf("%s", s)) { int top = 0, tail = 0; sum2 = 0; int x; memset(t, 0, sizeof(t)); l = strlen(s); for(i = 0; i < l; i++) { x = s[i]; t[x]++; } sum1 = 8 * l; for(i = 0; i < 500; i++) { if(t[i] != 0) q[top++] = t[i]; } qs(q, 0, top - 1); while(top != tail) { int x1 = q[tail++]; if(top != tail) { int x2 = q[tail++]; sum2 += (x1 + x2); q[top++] = x1 + x2; qs(q, tail, top - 1); } } printf("%d %d %.1lf\n", sum1, sum2, 1.0 * sum1 / sum2); } return 0; }