「字符串学习笔记」
Huffman树
严格意义上来说不算是字符串的内容,但是还是放在这里讲了。
一个很简单的模型,用来解决最优编码问题。
这个模型非常好理解,证明也非常显然,这里主要记录一下由 \(2\) 叉 \(\text{Huffman}\) 树推广到 \(k\) 叉 \(\text{Huffman}\) 树的过程。
下述证明约定,字符 \(x\) 的频率为 \(f(x)\)。
为了推广结论,我们需要证明两个性质:
- 贪心法选择,即最优解被包含在子问题的最优解中:设 \(x_1,x_2..x_k\) 是加权字符集 \(C\) 中频率最小的 \(k\) 个字母,则这 \(k\) 个字符在最优编码树中对应的节点必有共同的父亲。
- 最优子结构:设 \(T\) 是加权字符集 \(C\) 的最优编码树,\(x_1,x_2..x_k\) 是树中 \(k\) 个叶子,且这 \(k\) 个叶子互为兄弟节点,\(fa\) 为他们的父节点,若把 \(fa\) 看作具有频率为 \(\sum_{i=1}^kf(x_i)\) 的字符,则树 \(T'=T-\{x_1,x_2,..x_k\}\) 是字符集 \(C'=C-\{x_1,x_2,..x_k\}\bigcup fa\) 的最优编码树。
首先来证明第一个性质,若存在 \(y_1,y_2,..y_k\) 为加权字符集 \(C\) 的编码树 \(T\) 上深度最大的节点,不妨设\(f(y_1)\leq f(y_2)\leq..f(y_k),f(x_1)\leq f(x_2)\leq..f(x_k)\),则 \(f(x_1)\leq f(y_1),f(x_2)\leq(y_2)..,f(x_k)\leq f(y_k)\),若分别交换\((x_1,y_1),(x_2,y_2)..(x_k,y_k)\)后解也不会变得更差,于是得证。
第二个性质更加容易证明,设 \(T'\) 的编码长度为 \(L'\),其中 \({x_1,x_2..x_k}\) 的深度为 \(h\),那么 \(T\) 的编码长度为 \(L=L'-h\times\sum_{i=1}^kf(x_i)+\sum_{i=1}^k(h+1)\times f(x_i)=L'+\sum_{i=1}^kf(x_i)\),由于\(\sum_{i=1}^kf(x_i)\) 为定值,所以当且仅当 \(T'\) 最优时,\(T\) 是最优编码树。
于是 \(2\) 叉 \(\text{Huffman}\) 树的解法就推广到了 \(k\) 叉 \(\text{Huffman}\) 树,但是需要注意一点,由于 \(k\) 叉 \(\text{Huffman}\) 树在深度为 \(2\) 时,对于一些带权字符集 \(C\) ,不一定能够取满 \(k\) 叉,因此可能取不到最优解。我们可以在叶子节点处补若干个 \(f\) 值为 \(0\) 的节点,令其能够取满。这里给出一个结论,当叶子节点数 \(n\) 满足 \((n-1) \bmod (k-1)=0\) 时,必然在深度为 \(2\) 时能够取满 \(k\) 叉,也就能取到最优解。
证明也非常简单,对于一个 \(k\) 叉的最优 \(\text{Huffman}\) 树(在深度为 \(2\) 时能够取满),设其 \(k\) 度节点数为 \(n\),叶节点数目为 \(m\),则有 \(k\times n\) 条边。自然得到 \(k\times n = N-1,m+n=N\),联立可得 \((k-1)\times n=m-1\),于是有 \((m-1)\bmod (k-1)\)。注意,此处的 \(m\) 为叶子节点数,也就是上文的 \(n\)。
于是,\(k\) 叉 \(\text{Huffman}\) 树的求解就分为以下几个部分:
- 添加 \(f\) 值为 \(0\) 的叶子节点,令建立出的 \(\text{Huffman}\) 树一定是最优的。
- 仿照 \(2\) 叉 \(\text{Huffman}\) 树的解法,每次从堆中取出 \(f\) 值最小的 \(k\) 个节点,将他们的 \(f\) 值累加,作为新节点重新放入堆中,直到堆的大小为 \(k\),这个过程中在答案上每次累加这 \(k\) 个节点的 \(f\) 值。
- 最后的答案就是整个 \(\text{Huffman}\) 树对应的最小编码长度,可以根据上述过程建出 \(\text{Huffman}\) 树并求出每个字母对应的编码。
有一个很松的上界 \(O((\frac{n}{k}+n) \log (\frac{n}{k}+n)) \approx O(2n \log 2n)\),由于此类问题中 \(k\) 一般非常小,所以可忽略 \(k\) 对时间复杂度的影响。

浙公网安备 33010602011771号