每天一个知识点:分治算法:选择问题

选择问题的要求是找出含有 N 个元素的表 S 中的第 k 个最小的元素。

基本的算法是简单的递归策略。设 N 大于截止点(cutoff point),在截止点后元素将进行简单的排序,v 是选出的一个元素,叫做枢纽元(pivot)。其余的元素被放在两个集合 S_1S_2 中。S_1含有那些不大于 v 的元素,而 S_2则包含那些不小于 v 的元素。

为了得到一个线性算法,必须保证子问题只是原问题的一部分,而不仅仅只是比原问题少几个元素。这里要解决问题就是如何花费更少的时间来寻找枢纽元。

为得到一个好的最坏情形,关键想法是再用一个间接层。不是从随机元素的样本中找出中项,而是从中项的样本中找出中项。

基本的枢纽元选择算法如下:

  1. 把 N 个元素分成 「N/5」组,5 个元素一组,忽略(最多 4 个)剩余的元素。
  2. 找出每组的中项,得到「N/5」个中项的表 M。
  3. 求出 M 的中项,将其作为枢纽元 v 返回。

上面给出的枢纽元选择法,有一个专业的术语,叫做“五分化中项的中项”。“五分化中项的中项”保证每个递归子问题的大小最多是原问题的大约 70%。对于整个选择算法,枢纽元可以足够快的算出,以确保 O(N) 的运行时间。

定理:使用“五分化中项的中项”的快速选择算法的运行时间为 O(N)

降低比较的平均次数

分治算法还可以用来降低算法预计所需要的比较次数。

设有 N 个数的集合 S 并且要寻找其中第 k 个最小的数 X。我们选择 S 的子集 S‘,令 δ 是某个数,使得计算过程所用的平均比较次数最小化。

找出 S’ 中第 (v_1 = ks/N-δ) 个和第 v2 = ks/N+δ 个最小的元素,几乎可以肯定 S 中的第 k 个元素将落在 v_1v_2 之间,此时,问题变成了 2δ 个元素的选择问题。

经过分析,会发现,若 s\;=\;N^\frac23\;\log\left(\frac13\right)\;N\delta\;=\;N^\frac13\;\log\left(\frac23\right)\;N,则期望的比较次数为 N+k+O(N^\frac23\;\log\left(\frac13\right)\;N),除低次项外它是最优的。(如果 k>N/2,那么我们可以考虑查找第(N-k)个最大元素的对称问题。)

最后一项代表进行两次选择以确定 v_1v_2 的代价。假设采用合理聪明的策略,则划分的平均代价等于 N 加上 v_2 在 S 中的期望阶(expected rank),即 N+k+O(Nδ/s)。如果第 k 个元素在 S‘ 中出现,那么代价就是 O(N)。然而,s 和 δ 已经被选取以保证这种情况以非常低的概率 o(1/N) 发生,因此该可能性的期望代价是 o(1),当它的 N 越来越大时趋向于 0。

这个分析指出,找出中项平均大约需要 1.5N 次比较。当然,该算法为计算 s 需要浮点运算,这在一些机器上可能使该算法减慢速度。不过即使是这样,若能正确实现,则该算法完全能够比得上快速选择实现方法。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容