我觉得线性搜索实际上不是O(N),因为必须处理缓存未命中。这让我想知道为什么线性搜索仍然被宣传为具有时间复杂度O(N)?难道不应该考虑存储器单元与CPU的“距离”吗?除了由于光速而导致的信号传播是没有人可以逃脱的物理限制。在这里,我正在讨论经典而非量子计算。
让我们快速分析一下现实世界中线性搜索算法的合理界限。让我们假设一个无限小的CPU被封装在球形质量的存储单元的中心。使用恒定数量的晶体管k来实现每个单元。每单位体积的晶体管数量是rho。 CPU具有读/写线和每个存储单元的数据线(假设路由这些线路不是问题),并且CPU只能在任何时刻读/写一个位。在这里,我们需要找到在N个存储位上执行线性搜索所需的时间。
(没有足够的代表发布图片,但这里是一个图表的链接,我试图说明问题) http://img51.imageshack.us/img51/7361/searchqn.png
球体半径
所需的总体积为N * k / rho。给定包含所有存储单元所需的球的半径为R,我们得到(4/3)* pi * R ^ 3 = N * k / rho,或者R = a * N ^(1/3)一些常数a。
元素壳dV(r)
考虑元素shell dV(r)= 4 * pi * r ^ 2 * dr(图中的灰色壳),其中包含驻留在其中的dV * rho / k存储位。 CPU需要不小于2 * r / c的时间来读取/更新驻留在该dV内的存储器位(首先断言R / W线,然后期望来自存储器单元的响应),其中c是速度光明。
整合dt
与驻留在dV(r)中的所有存储器单元接口所花费的时间由dt =(以dV为单位的单元数)*(与每个单元接口所花费的时间)=(8 * pi * rho * r ^ 3) * dr)/(k * c)= b * r ^ 3 * dr为某些常数b。所用的总时间T将是b * r ^ 3相对于r的积分r = 0..a * N ^(1/3),这给出了我们T =(b * a ^ 4 * N ^(4/3))/ 4 = O(N ^(4/3))。
我不认为这种分析是过度的,因为现在计算机系统中的三级缓存并不罕见。很快(谁知道)可能存在多层存储器模型,其中存储器单元与CPU的距离可以被认为是连续的。
PS:对于那些感兴趣的人来说,存储单元线性布局并在圆盘上均匀布局的时间复杂度为O(N ^ 2)和O(N ^(3) / 2))。我相信,就CPU和存储单元之间的高效接口而言,晶体管在球体中分布的情况是最佳方式。
答案 0 :(得分:5)
算法是基于理论的,时间复杂度是在类似图灵机的基础上计算的,其中存储器本身被认为不同于标准计算机(以及处理存储器和操作的许多其他自动机不同)。复杂性描述了一种模式,在给定一组应该完成的基本指令的情况下,基本操作将用于计算问题的答案。因此,时间复杂度为O(n)。您所说的复杂性大多是非常精细的优化,除非您在非常具体的时间做某些事情,否则这些优化并不是必需的。当您确定要使用的算法时,这种分析没有标准算法分析那么多的含义。
就我而言,我会更关心这些细粒度数据,这些数字因CPU和其他因素的不同而不同,并考虑到能够更快地实现我所需要的东西。这些被称为微优化,它们只是为了利用硬件特定的变化,通常应该保留到最后。在大多数情况下,所有或大多数硬件都会表现出相同或接近相同的复杂性(有一些例外,例如SSE优化)。
答案 1 :(得分:2)
计算复杂性取决于算法执行的操作数量,并未考虑执行算法的实际计算机中的非线性行为。
可能更好的说法表现不仅仅是复杂性。
一个类似的例子是后缀trie算法,其中Ukkonen的线性算法由于其较差的内存局部性而经常比其他具有更高复杂度的算法表现更差。
答案 2 :(得分:1)
在计算big-O时,有助于将程序的成本视为指向n空间的向量,其中n是您正在分析的维数。
其中一个轴是计算复杂性,这是我们的大O.因为我们使用单次运行来代表这种复杂性(我使用“run”松散地表示具有一些定义输入的代表性程序),我们可能会选择计算复杂性(读取:循环复杂性)作为鉴别器。我已将“big-O”重命名为“comp_complexity”以澄清事情:
Cost(program, n) -> <comp_complexity(program, n)>
其中program
是我们正在分析的程序(带有输入)的坐标,n
是集合中元素的数量。可能我们知道此向量的computational_complexity
维度可以使用字大小或其他输入。
Cost(p,n,m) -> <comp_complexity(p,n,m)>
我们可能会添加一些会影响计算复杂性的事情:空间复杂性或运行程序的挂钟时间。所以我们添加了额外的维度(我选择a
作为时钟时间的任意输入):
Cost(p,n,m,a) -> <comp_complexity(p,n,m),
space_complexity(p,n,m),
wall_clock(p,n,m,a)>
所以Cost
返回一个函数向量,它根据输入返回一些成本。而我们可能追求的是给定实际成本的大小,|Cost('bubble_sort',10,20,1.3)|
,或更可能的是,该成本的某些预测的大小(在现实生活中,我们可能在一般情况下一次解决一个线性最大狩猎,希望有一些美丽的理想解决方案)。可能肯定会有隐藏的成本我们忽略了,但我们调查的目的是减少我们设定的投影幅度,如果不是对整个输入范围,那么可能是为了一些小窗口。为了降低成本向量的大小,我们可以投入精力来降低与其任何轴相关的成本,无论是计算复杂性还是方法的完整运行时间,还是所涉及的代码的维护成本。 / p>
因此,为了回答您的问题,线性搜索分析的一个方面是其内部循环的复杂性,Big-O,Cost<n> = <n>
。这并不意味着它是算法成本的最大贡献者,但如果这个一维投影是我们所关注的,那么它在改进我们已有的东西时提供了一种比较的衡量标准。