更糟的是更好。 有一个例子吗?
是否有一个广泛使用的algorithm的时间复杂性比另一个已知的algorithm更差 ,但是在所有的实际情况下它是一个更好的select(复杂度更高但是更好 )。
可接受的答案可能是一种forms:
有algorithm
A
和B
地具有O(N**2)
和O(N)
时间复杂度,但是B
具有如此大的常数,以至于对于input小于宇宙中的primefaces数量,它不具有A
优点。
答案中的例子突出显示:
-
单纯形algorithm – 对于凸优化问题,最坏情况是指数时间 – 已知多项式时间algorithm。
-
中值algorithm的朴素中位数 – 最坏情况O(N ** 2) 与已知的O(N)algorithm。
-
回溯正则expression式引擎 – 最坏情况下的指数与 O(N)Thompson NFA引擎。
所有这些例子都是利用最坏情况与平均情况。
是否有例子不依赖于最坏情况与平均情况之间的差异?
有关:
-
“更坏更好”的崛起 。 (为了这个问题的目的,“更糟糕更好”这个短语的使用范围比文章更窄 (即algorithm时间复杂度)
-
Python的devise理念 :
ABC集团追求完美。 例如,他们使用基于树的数据结构algorithm,这些algorithm被certificate对于渐进式大集合是最优的(但对于小集合来说并不是那么好)。
如果没有能够存储这些大集合的计算机(换句话说,在这种情况下大不够大),这个例子将是答案。
-
方matrix乘法的Coppersmith-Winogradalgorithm是一个很好的例子(它是最快的(2008),但是差于algorithm)。 其他人? 从维基百科文章:“这不是在实践中使用,因为它只提供了一个巨大的优势,他们不能被现代硬件处理(罗宾逊2005年)”。
快速sorting的最坏情况下的时间复杂度为O(N ^ 2),但通常认为在最坏的情况下比其他sortingalgorithm具有O(N log n)的时间复杂度更好。
单纯形是一种在最坏的情况下具有指数时间复杂度的algorithm,但对于任何实际情况它是多项式的。 可能存在用于线性规划的多项式algorithm,但它们非常复杂并且通常具有较大的常量。
在语言中也可以看到“更糟糕更好”,例如Perl,Python,Ruby,Php甚至C#或Java,或者任何不是汇编器或C(C ++可能适用于此)的语言。
基本上总是有一个“完美”的解决scheme,但是多次使用“更差”的工具/algorithm/语言来获得更快的结果,而且痛苦更less。 这就是为什么人们使用这些更高级的语言,虽然他们从理想的计算机语言angular度来看是“更糟糕的”,而是更加以人为本。
蒙特卡洛积分是计算定积分的概率方法,不能保证返回正确的答案。 然而,在现实世界的情况下,它比准确的方法返回准确的答案要快得多。
方matrix乘法的Coppersmith-Winogradalgorithm 。 它的时间复杂度是O(n 2.376 ) 与 O(n 3 )的一个天真的乘法algorithm或O(n 2.807 )的Strassenalgorithm 。
从维基百科的文章:
然而,与Strassenalgorithm不同的是,它并没有在实践中使用,因为它只为matrix提供了一个很大的优势,使得它们不能被现代硬件处理(Robinson 2005)。
这个陈述可以应用于几乎所有的并行algorithm 。 他们之所以没有在计算机初期进行大量的研究,是因为对于单线程的执行(认为是单处理器)来说,他们确实比他们众所周知的顺序对应的慢渐进复杂性,小n的常数因子,或两者。 然而,在当前和未来的计算平台的背景下,一个可以利用less数几个(想到多核),几百(想象GPU)或几千(想超级计算机)处理元素的algorithm将击败序列版本即使在并行版本中,所有处理器花费的总时间/能量也要大得多。
sorting,图algorithm和线性代数技术都可以通过花费一些额外的簿记,通信和运行时间开销来平行化,从而加速挂钟时间。
通常,一个algorithm(比如快速sorting )可以很容易地进行并行化或随机化,而不是竞争性的algorithm,这些algorithm缺乏这些特性。 而且,当一个精确algorithm产生像旅行商问题那样的指数运行时间时,通常情况下问题的近似解是可接受的。
如果没有能够存储这些大集合的计算机,这个例子将是答案。
据推测,收集的大小是641K。
在为各种飞机devise结构和空气动力学代码的BAE SYSTEMS公司的技术计算部门工作时,我们的代码库至less可以追溯到25年前(三分之一的工作人员在那里呆了很长时间)。
许多algorithm都针对16位主机的性能进行了优化,而不是针对可扩展性。 这些优化对于20世纪70年代的硬件来说是完全合适的,但是在32位和64位系统上取代它的较大数据集上performance不佳。 如果您select了一些可扩展性较差的产品,而这些产品在您当前正在使用的硬件上运行得更好,请注意,这是一种优化,将来可能不适用。 在20世纪70年代编写程序的时候,我们在21世纪的数据大小是不实际的。 不幸的是,试图从这些代码中提取一个清晰的algorithm,然后可以实现,以适应现代硬件不是微不足道的。
海洋沸腾之后,“所有实际情况”都是一个时间variables。
不太符合标准,但基于回溯的正则expression式与基于DFA的正则expression式的O(N)相比具有指数性的最差情况,但基于回溯的正则expression式几乎总是被使用,而不是基于DFA的正则expression式。
编辑:(JFS)
正则expression式匹配可以简单而快速(但在Java,Perl,PHP,Python,Ruby,…中速度较慢) :
反向引用的function需要很高的代价:在最坏的情况下,最着名的实现需要指数searchalgorithm。
正则expression式引擎 :
这种方法(DFA)确实更高效, 甚至可以适应捕获和非贪婪匹配 ,但它也有重要的缺点:
- Lookarounds是不可能的
- 反向引用也是不可能的
- 正则expression式预编译时间更长,需要更多的内存
在光明的一面,以及避免最坏情况下的指数运行时间,DFA方法避免了input数据大小呈线性的最坏情况下的堆栈使用情况。
[3]:
基数sorting对于固定长度的input具有时间复杂度O(n),但是尽pipe更糟糕的asympotic运行时间,但更常使用快速sorting,因为基数sorting上的每元素开销通常要高得多。
好的,考虑解决旅行销售人员问题。 唯一完美的解决scheme是testing所有可能的路线。 然而,随着N的增加,我们的硬件和时间限制变得不可能。 所以我们想到了很多启发式的东西。
哪个把我们带到你的问题的答案。 启发式(更坏)比NP完全问题的蛮力更好。 这描述了“更糟糕更好”的情况总是如此。
如果我理解了这个问题,那么你所要求的algorithm在理论上会更好,但在所有情况下都会更差。 因此,除非错误,否则不会期望它们被实际使用。
一个可能的例子是通用记忆 。 理论上讲,所有确定性的函数调用都应该logging下所有可能的input。 这样复杂的计算可以被简单的表查找所取代。 对于广泛的问题,这种技术可以高效地为存储空间交易时间。 但是,假设所有人类计算机都使用了所有可能function的所有可能的input结果的中央存储库。 任何地方的人第一次做了计算,这将是最后一次。 所有后续的尝试将导致表查找。
但是我可以想到,有几个原因是不这样做的:
-
存储所有结果所需的内存空间可能会很大。 似乎可能需要的位数将超过宇宙中的粒子数量。 (但即使估计这个数字的任务也是令人生畏的)。
-
构build一个有效的algorithm来logging这个庞大的问题空间是很困难的。
-
随着客户数量的增加,与中央仓库沟通的成本可能会超过收益。
我相信你可以想到其他问题。
事实上,这种时间/空间的折衷在实践中是不可思议的。 理想情况下,所有数据都将存储在L1caching中,但由于大小限制,您总是需要将一些数据放在磁盘或(恐怖)磁带上。 先进的技术减less了这些权衡的一些痛苦,但是正如我上面所提到的,这是有限度的。
为了回应JF Sebastian的评论:
假设我们不考虑通用存储库,而是考虑一个因子存储库。 它不会保留所有可能的input的结果。 相反,它将被限制在从1
到N!
结果N!
现在很容易看到,任何计算因子的计算机都将从查找结果中获益,而不是进行计算。 即使计算(N+1)!
查找将是一个巨大的胜利,因为计算将减less到N!(N+1)
。
现在为了使这个“更好”的algorithm变得更糟,我们可以增加N或者增加使用版本库的计算机的数量。
但是我可能不了解这个问题的一些微妙之处。 他们以这种方式思考,我不断地提出可以扩展的例子,直到他们没有。
存在确定素性的多项式时间algorithm,但是在实践中,使用指数时间algorithm或者执行足够的确定性的足够的概率计算总是更快。
Mergesort与Quicksort
快速sorting的平均时间复杂度为O( n log n )。 它可以对数组进行sorting,即空间复杂度为O(1)。
合并sorting的平均时间复杂度为O( n log n ),但是其空间复杂度更差 :Θ( n )。 (链表有特殊情况)
由于最坏的情况,快速sorting的时间复杂度是Θ(n ^ 2)(即所有元素落在每个枢轴的同一侧),mergesort的最坏情况是O( n log n ),mergesort是库的默认select实施者。
在这种情况下,我认为mergesort的最坏情况时间复杂性的可预测性胜过了快速的内存要求。
鉴于有可能大大降低最坏情况下快速sorting的时间复杂性(例如通过随机select主键),我认为有人可能会认为合并速度更快,除了快速sorting的病态情况。
在计算一组数字的中位数时,可以使用与快速sorting非常相似的algorithm。 你围绕着一个数字进行分区,所有较大的数字都在一边,而所有较小的数字都在另一边。 然后你扔掉一边,recursion地计算大一边的中位数。 这在最坏的情况下需要O(n ^ 2),但是在平均情况下相当快(O(n)具有低常数)。
你可以得到保证最坏情况的O(n)性能,常数约为40.这被称为中位数algorithm 。 在实践中,你永远不会使用这个。
一个例子是来自计算几何。 由于Chazelle的 多边形三angular剖分algorithm具有最坏的O(N)algorithm,但由于实现的韧性和巨大的常数,在实践中几乎没有实现。
我一直都明白“更糟糕更好”这个术语与正确解决scheme的问题有关,这些解决scheme在存在比较容易理解的近似(或足够好的)解决scheme时非常复杂。
这使devise,生产和维护更简单。
有一个O(n)algorithm用于从未sorting的集合中select第k个最大的元素,但是它很less用来代替sorting,这当然是O(n logn)。
尽pipe具有O(n 2 )复杂性,插入sorting对于小集合(n <10)比任何其他sortingalgorithm更快。 这是因为嵌套循环很小,执行速度很快。 许多实现了sorting方法的库(包括STL)实际上将其用于小数据子集来加快速度。
已经提出了蒙特卡罗整合,但更具体的例子是蒙特卡罗在金融方面的定价也是一个build议。 这里的方法更容易编码,可以做比其他更多的事情,但它比说有限的差别慢得多。
它不适合做20维有限差分algorithm,而20维的定价执行很容易build立。
意大利式sorting比任何其他sortingalgorithm都好,因为它是O(n)设置,O(1)执行,O(n)提取sorting后的数据。 它在O(n)空间复杂性中完成了所有这些。 (总体performance:O(n)在时间和空间上都是这样。)然而,对于一些奇怪的(显而易见的)理由,没有人使用它,更喜欢O(nlogn)algorithm等等。
迭代深化
当与用α-β修剪增强的平凡深度优先search相比,与穷(或不存在)分支sorting启发式结合使用的迭代加深search会导致更多的节点被扫描。 然而,当使用良好的分支sorting启发式时,由于α-β修剪的增强效应,树的大部分被消除。 与时间或空间复杂度无关的第二个优点是,对问题域的解决scheme的猜测是早期build立的,随着search的进行,猜测会变得更加精确。 这是第二个优点,使它在许多问题领域如此吸引人。
Quick-sort has worst case time complexity of O(N^2)! It is considered better than other sorting algorithms like mergesort heapsort etc. which have O(N log n) time complexity in the worst case. The reason may be the 1.in place sorting 2.stability, 3.very less amount of code involved.