哈夫曼编码(字符串压缩)

之前去面试,被面试官问到这么一个问题:

假如现在有一个设备,仅允许输入a~z以及空格这27个字符,请问,如何编码保存,能使其占用的内存空间最小?

刚开始答的时候,想到了用asc编码的形式,将27个字符分别用27位十进制数字进行保存,之后再将这27个十进制数字转为二进制存储到硬盘中,其占用的大小小于 25 字节(00000~11111),之后面试官又问:

如果当前字符串是连续的多个字符组成的,如何优化存储方式?

想了一会儿还差一点,面试官提示说可以进行标记,然后跟我讲,用剩下的五位(11100~11111)存储特殊字符(比如存储一个“#”)对每个字符进行标记存储,例如 #a#50# 就表示连续的五十个a #abc#100# 就表示连续的一百个 abc 用这种方式就可以做到连续的字符用定长存储,最后面试官又问:

如果这一串字符中,有的字符出现的概率十分大,有的字符出现的概率很小,怎么去优化存储空间呢?

这里答得不是很好,具体用到的数据结构应该是哈夫曼编码,所以在这复习一下哈夫曼编码。

哈夫曼编码(Huffman Coding)是一种编码方法,它使用变长的编码表对源符号进行编码,其中变长编码表是通过一种对字符出现几率统计的方法得到的,出现几率高的字符使用较短的编码,反之采用较长的编码,由此可以使得编码之后的字符串的平均长度、期望值降低,从而节省存储空间、达到无损压缩数据的目的。

编码的过程如下

  1. 将源符号按概率大小进行排序(从大到小)
  2. 将两个概率最小的合并,并继续这一步骤,始终将较高的概率分支放在右边,直到最后编程概率1。
  3. 将每对组合的左边指定为0,右边指定为1。
  4. 画出由概率1处到每个源符号的路径,并按顺序记下路径的0和1,所得到的编码即为该符号的哈夫曼编码。

举个栗子:给定字符串DABBBCEABDCEBDCBEDCBBAECBDCBDA

  1. 首先计算出每个字符出现的概率(按出现的次数进行计算):
    =SUMPRODUCT(LEN(B1)-LEN(SUBSTITUTE(B1,“E”,""))) 使用函数进行统计分析。
    哈夫曼编码(字符串压缩)_第1张图片
  2. 把出现次数最小的两个相加,并作为左右子树,重复此过程。
    哈夫曼编码(字符串压缩)_第2张图片
  3. 将树的左右子树分别标记01。
    哈夫曼编码(字符串压缩)_第3张图片
  4. 按二叉树从根到叶子结点,获取字符编码
    哈夫曼编码(字符串压缩)_第4张图片
    从这个图可以看出,出现次数越多的字符,越在上层,编码越短,出现次数越少的,越在下层叶子结点,编码越长,且每一个字符的编码都与另一个字符编码的前一部分不同,解码不会冲突。

你可能感兴趣的:(基础编程)