主方法
主方法(master method
)用于分析递归算法的时间复杂度。
主方法也是一个标准的递归式子。当 时,,其中 是常量。也就是说,当 很小的时候,时间复杂度是 。当 很大时,递归式子是 其中 是常量。一般而言, 是任意正整数; 是大于 1 的实数,如果 ,递归时算法的规模没有减少,那么整个算法无法收敛; 是非负实数,如果 ,那么递归之外只需要 就能完成工作。
如果 定义如上,那么
从上面式子中,可以看出来 和 的大小关系非常重要。
另外,第一种情况对数没有写底数,因为这不重要,底数是不同常量的话,差一个常量系数罢了,一般用 2 作为底数。但是第三种情况要写明底数,因为差的这个系数在指数的位置,那么时间复杂度就差 这么多了,比如 和 差距是很大的。
在证明上面的等式之前先给两个简单的例子。
归并排序中,两次递归调用,因此 ,每次规模缩小一倍,因此 ,对两个已排序数据进行合并, 的时间复杂度,因此 ,那么 ,那么时间复杂度是 。
二分查找,只有一次递归调用,,每次规模缩小一倍,因此 ,除了递归之外,进需要比较 key 和中间值,,因此 ,因此 ,那么时间复杂度是 。
下面给出主方法的证明。证明过程很重要,并不是因为关心其形式,而是证明过程能够解释主方法的本质,比如为什么有三种不同的类型。因此值得记住理解的不是证明过程中的代数运算,而是主方法三种情况的含义。
稍微简化一下要证明的式子,这并不影响证明的思路和正确性。首先令 ,即基本情况是 。当 时 这里使用了同一个常量 ,如果实际中两者不同,取更大的即可。这里假定 是 的若干次幂,这样可以简化证明。
下面是递归调用的过程。
第 层有 个子任务,每个任务的输入规模是 。那么不计算递归调用的时间复杂度是 稍微改写一下 这就出现了结论中很重要的一个比值:。
一共有 层,那么总的复杂度是
第一种情况,,那么 最后一个步骤忽略了常量 。
直观的看,,子问题增加的 与工作减少的比率 一样多,那么每层的工作量是相同,共有 层,层数乘以 就是总工作量。
第二种情况, 时 其中 。
直观的看, 时,子问题增加的速率要比工作量减少的比率要小很多,也就是根节点工作量最大,也就是 权重更大。这个第三种情况恰好相反,叶子节点权重最大,而叶子节点是第 层,那么时间复杂度为 1 的叶子节点个数是 ,这也就是总的复杂度。
第三种情况, 时 其中 。 几何级数求和可以缩放为 那么 那么时间复杂度是 和 还差一步: 由于 , 是单调递增函数,因为 。