这篇文章是关于本学期课程《数据结构》课本中一个问题的补充。早在一个月前就被大佬ZWC同学怂恿写这篇博客,但是由于太懒一直拖到现在。
这个问题源自Cormen《算法导论》对应章节的一个课后题,解法源自图灵奖得主D. E. Knuth在1970年发表的一篇论文。(所以说这个课后题真的有点难!)先简单地说一说最优二叉树的原始算法,再看看Knuth 对这个算法的refinement——从
Part 1 问题描述
最优二叉树(Optimum Binary Search Tree) 指对于给定节点构造出的权重和最小的二叉树。设有带权全序节点集合
达到最小,其中
一个简单的例子是字典的编排:把单词连同它出现的频率作为节点放在二叉树中。当我们需要查询一个单词时,从根节点出发按照二叉树查找的方法找到这个单词。一个直观的判断是:频率出现高的单词应当放得更加靠近根位置,不太可能出现的单词要放在尽可能深的位置。事实上,这个猜测并不完全正确。
考虑由A, B, C三个节点,他们的序关系A<B<C。当它们的权重按照下面两种分配方式进行时,最优二叉树分别为:
注意,在第二种情形下,B节点的权重最小,但是它却是最优二叉树的根节点。所以构造最优二叉树的方法一般来说没有什么捷径可言。
Part 2 原始算法(枚举法)
原始的最优二叉树求法近似于枚举法。对于任意一个最优二叉树
这样一来,我们所要做的就是输出一个矩阵
于是对于给定的长度
假设已经得到了
则权重和是左边加右边加中间:
之所以出现w项,是因为把k节点加入二叉树时,我们其实把左右子树中每一个节点的深度都加了1个单位。这样我们就可以利用长度小于l的结果计算长度为l的结果了。算法的伪代码表示如下:
Optimal Binary Search Tree (vector a[i], vector p[i]):
1 new matrix e[i][j] and w[i][j] and r[i][j], #i,j from 1 to n
2 for i from 1 to n:
3 e[i][i] = p[i]
4 w[i][i] = p[i]
5 for l from 2 to n: #子树长度从2开始
6 for i in range(n):
7 j = i + l -1
8 e[i][j] = infty #初始化
9 w[i][j] = w[i][j-1] + p[j] #by definition
10 for k from i to j:
11 tmp = e[i][r-1] + e[r+1][j] + w[i][j] #(*)式计算权重和
12 if t < e[i][j]:
13 e[i][j] = tmp
14 r[i][j] = k
15 return e, r
注意到这个程序的输出是上面提到的矩阵,和最终计算的权重和。第五行开始的for循环固定了子树的长度,第六行跑遍所有长度为l 的子树;第10行的for循环则是一个一个尝试范围内的节点作为子树的根节点并计算权重和,类似于枚举法。实现的代码参见:
Optimal Binary Search Tree | DP-24 - GeeksforGeekswww.geeksforgeeks.org显然,这个算法的时间复杂的是三次方的,因为前后一共嵌套三个跑遍所有取值的for循环。
Part 2 Knuth的改进
有一说一,Knuth的改进并不是本质的。这个改进通过观察加入一个节点时整个二叉树的变化出一般规律(但是我认为发现这个规律需要极高的天才);这个规律告诉我们:在上述第十行的循环里,并不需要尝试所有的i , j范围内的节点,因为有些节点不可能成为最优子树的根节点!
沿用上边的记号,我们先证明下面的引理:
Lemma 考虑在最优二叉树
(注意,此处的n指标仍然包含节点key值的序关系,也就是说,第n个节点是所有n个节点中key值最大的。)
Proof: 记
第一条的意思是,增加第n个0权重节点不会改变整个树的权重和:这是显然的。
第二条的意思是,增加一个0权重最大节点,所有
(利用第一条)
另一方面,多加一个节点不会使得最优树的总权重降低:
Remark: 这个引理保证了主要定理归纳法的前提。证明看似平凡,是因为我简化了问题:原问题还包含着找不到key时返回的dummy keys,它们构成最优二叉树的所有叶子结点,情况更加复杂。
下面是核心定理:
Theorem: 对于一个最优二叉树
其中的不等号指的是key值的序关系。也就是说,左边加小节点,根节点不变大;右边加大节点,根节点不变小。这里的大小指的是key值的大小。
先来看这个性质如何将复杂度降为
也就是说,在伪代码第10行开始的循环中,我们不需要一个一个检查所有的节点是否可以成为
这其实是一个裂项和!为更清楚一些,设l=4,写出求和式:
所以结果是一个常数,而非n.
下面给出定理的证明:
Proof: 在引理中我们已经得知当新节点为零权重时,结论成立。下面用归纳法证明对于任意大的新节点权重,上式仍然成立。
设
其中d和d' 分别为
由(1)和
故
即
取
这意味着在
考虑两棵树的右边:
由反设假设,
另一方面,由于
事实上,分别记
故不需要让节点左移。Q.E.D.
ps: 十分感谢ZWC同学对本文的校对,以及给我指出最后一个命题的正确证明。
参考文献:
- D. E. Knuth: Optimum Binary Search Tree, Acta Informatica 原文链接:
2. Thomas H. Cormen: Introduction to Algorithms, 3rd edition, chapter 15.5, mit express.
相关书籍:
- 严蔚敏吴伟民《数据结构》清华大学出版社