最优哈夫曼树是啥
有篇文章(字符串),想把它加密成01串。所以要给每个字符映射一个01串代表它,而且一个字符的01串不能是另一个的前缀,否则将出现二义性。所以可以把一颗二叉树的叶子节点看成字符,向左走和向右走分别为0和1,这样构造映射到的01串就不会有二义性,这个树就是哈夫曼树。为了使得01串总长度最小,就要构造最优哈夫曼树。显然每个字符的01串长度是字符节点的深度(到根节点经过的变数),所以使得
l
e
n
=
∑
c
n
t
i
∗
d
e
e
p
i
,
i
∈
σ
len=\sum{cnt_i*deep_i},i\in\sigma
len=∑cnti∗deepi,i∈σ
最小。
其中
c
n
t
i
,
d
e
e
p
i
,
σ
cnt_i,deep_i,\sigma
cnti,deepi,σ分别表示字符i出现的次数,字符i的叶子结点深度,字符集合。以下n是字符集大小。
算法步骤简介
采用贪心算法。一开始节点集合有n个字符节点,每个节点权为字符权重。每次选择剩下的节点中选两个权重最小的,合并成一个新节点,权重为两节点之和。删除两个节点,移入新节点。旧的两个节点就是新节点的左右儿子。知道集合里只有一个节点。
复杂度
每次集合减少一个点,用优先队列模拟选点过程的话,时间为 T = ∑ i = 2 n l o g 2 i + l o g 2 ( i − 1 ) = O ( n l o g n ) T=\sum_{i=2}^{n}log_2i+log_2(i-1)=O(nlogn) T=i=2∑nlog2i+log2(i−1)=O(nlogn)
算法正确性证明
众所周知,贪心算法要满足最优子结构和第一步正确性。
-
所以我就从这两方面下手:
1.第一步正确性证明:
令n个结点中最小的两个是x,y。就是证明们对于n个叶子节点的哈夫曼树,开始选x,y合并是可以构造可以出哈夫曼树的。即证明n个叶子节点的最优哈夫曼树集合中,一定有一棵,x,y处于层数最深的那层,且互为兄弟。-
(1) 层数最深证明:
现在有一棵按算法构造的树T,加密01串总长 度len。如果把层数比较浅的叶子z节点(按算法 c n t z > = c n t x cnt_z>=cnt_x cntz>=cntx)和 x交换,那么新的总长度 l e n ′ = l e n + ( d e e p z − d e e p x ) ∗ c n t z − ( d e e p z − d e e p x ) ∗ c n t x = l e n + ( d e e p z − d e e p x ) ∗ ( c n t z − c n t x ) ≥ l e n len'=len+(deep_z-deep_x)*cnt_z-(deep_z-deep_x)*cnt_x\\ =len+(deep_z-deep_x)*(cnt_z-cnt_x)\\ \ge len len′=len+(deepz−deepx)∗cntz−(deepz−deepx)∗cntx=len+(deepz−deepx)∗(cntz−cntx)≥len
所以交换深度一定不会让总长度变小。所以x,y一定层数最深的这棵树一定是最优的。 -
(2) x,y是兄弟证明:同层交换不改变总长度。所以某棵树xy不在一起的话,根据层数最深规则xy一定在同一层。所以设y现在的兄弟是z,把x和z换一下最优性不变而使得xy互为兄弟。所以一定有一棵最优树x,y互为兄弟。
-
到这里第一步正确性就成立了。
-
- 最优子结构:
这个比较好办。现在是n个点,弄完第一步后剩n-1个点,要证明这n-1个点也得构成最优树才能保证n个点也是最优树。证明:
设n-1个点构成了T‘树,总长度为len’。此时n个点的树的 l e n = l e n ‘ + c n t x + c n t y len=len‘+cnt_x+cnt_y len=len‘+cntx+cnty显然len’最优才能保证len最优。
- 所以满足最优子结构和第一步正确性,算法是合理的。