java - 如何设计一个高效的排序对手?
问题描述
理论上,我们知道基于比较的排序算法的比较次数是 ceil(lg(n!)),其中 lg 代表以 2 为底的对数。
我们可以建立一个对手,我们通过计算偏序的线性扩展数来选择排序,如果小于或大于这两种情况。无论哪个具有更高的线性扩展,都选择该路径。(这会自动处理不一致,因为如果回复在一侧不一致,它将为零,其他将与前一个相同)
然而,这样的对手效率不高,因为计算部分顺序的线性扩展数是#P-complete。
另一种选择是使用更简单的多项式时间对手,它可以:
- a > b 如果 a 从未输过,并且 b 至少输过一次。
- a > b 如果双方都不败,并且 a 的胜场数比 b 多。
- a > b 如果偏序强制 a > b
- a < b 如果偏序强制 a < b
- 选择任何其他。
这个对手取自计算机编程艺术,第 3 卷,第二版,第 209 页。它非常适用于查找第二大元素等问题,因为它强制进行 n + ceil(lg(n)) - 2 次比较。不幸的是,它并没有强制信息理论界进行排序。即使我添加了更多启发式方法,例如支配计数(大于的值的数量)来比较而不是随机选择顺序,这仍然是正确的。
我知道它不会强制,因为 Java 8 中的 Collections.sort() 在下限为 75 时对 74 次比较中的 23 个元素数组进行排序。源代码显示,对于所有小于 23 的数字,它能够强制下限,对于 100 个数字,sort() 在下限为 525 时设法进行 in506 比较。
是否存在一个多项式时间有效的对手,它迫使排序算法至少使用信息论界限?
解决方案
有一个“可能近似成功”的多项式时间对手,它使用随机化(例如)强制 ceil(lg(n!) - n -100 ) 以至少 1 - n -100的概率进行比较。
关键思想是,虽然计算线性扩展的数量很困难,但采样均匀随机扩展很容易(至少是多项式时间),因此我们可以对 a < b 的扩展数量进行大概正确的估计与 a > b 相比。显然,如果计数足够接近,我们无法判断哪个更有可能,但是通过获取足够的样本(但仍然是多项式数),我们可以证明使用 Hoeffding 界,其概率至少为 1 - n -102,对手选择的结果至少与线性扩展的 1/2 - n -102部分一致。我们可以将这些错误的累积效应限制在 n -100范围内。
推荐阅读
- c# - 如何通过连接从 SQL Server 转换为 Linq?
- angular - Angular 6将数据从组件传递到不相关的组件
- python-3.x - python 根据主机名从复合日志文件中分离行
- c# - 找不到dll文件
- javascript - Javascript:给定一个变量数组,删除字符并输出另一个数组的函数
- r - 带有列表 R 的 for 循环
- nginx - nginx proxyPass 到 prometheus 使用变量
- talend - Talend 不在 0 行执行组件
- android - URL.decode 不适用于字符串
- javascript - 正则表达式匹配两行