渐近符号 - n(log n)(log n)是否简化?

时间:2009-10-25 05:33:30

标签: algorithm theory asymptotic-complexity

如果我有一个算法需要n个n步骤(例如heapsort),其中步骤需要log n时间(例如比较/交换0到n-1范围内的“大”整数),什么是渐近的对整个过程的约束。

显然我们可以说“n(log n)(log n)”,但是我很难说服自己我不能简化为“n log n”。与此同时,我很难证明我坚持自己的本能。

我的直觉在这方面是否明显错误?

修改

似乎我的简单例子 - 避免 - 复杂化问题使问题复杂化。哦,好吧。

问题的真正原因是我经常使用具有已知复杂性的标准算法,但使用不同的底层容器实现,因此各个步骤是O(log n)而不是O(1)。例如,Hopcrofts自动机最小化算法是O(n log n) - 但是如果你开始使用二进制树容器来处理状态,转换和中间结果,那么步骤本身就变成O(log n) - O(n log n)是不再有效,因为O(1)访问的假设无效。

仍然,人们会声称有n个状态和m个转换,但是n和m往往与自动机线性相关,假设转换注释的数量是恒定的并且自动机是或多或少的确定性。

我过去对此并不太担心 - 与我合作的案例并不是很大。但是,好吧,我正在对我的自动机代码进行重大的重构,并且我认为我可以正确地为一些关键算法进行数学运算。

修改

我也越来越相信“n(log n)(log n)”是错误的。

如果a是O(b log b),其中b是O(log c),那么就c来说是什么?

4 个答案:

答案 0 :(得分:5)

通常,您不能将这样的复杂性加倍:对于堆排序,N表示堆中的项数,而对于大整数,N可能表示可能值的上限。一般来说,这些不必相关,因此它相当于N log N log M(其中M是项目可能采用的范围)。

在特定的应用程序中,大多数情况下,大整数遵循一些特定的分布。例如,可以知道它们都低于10 ^ 20。如果是,则比较操作采用恒定时间(由10 ^ 20的上限确定)。然后,log M也是常数,整个复杂度在O(N log N)。

答案 1 :(得分:3)

这是一个矛盾的证据:

假设函数f(n)= n(log n)(log n)。假设我们认为它也是theta(n log n),所以换句话说,对于大n,有一个f(n)< = a * n log n。

现在考虑f(2 ^(a + 1)):

f(2 ^(a + 1))= 2 ^(a + 1)* log(2 ^(a + 1))* log(2 ^(a + 1))= 2 ^(a + 1 )* log(2 ^(a + 1))*(a + 1),它明显大于a * 2 ^(a + 1)* log(2 ^(a + 1)),我们有矛盾。因此f(n)不是n log n函数。

答案 2 :(得分:2)

您将无法将n (log n) (log n)简化为n (log n),因为这不是一个常数因素的减少。

n (log n) 2 出了什么问题?

答案 3 :(得分:1)

好的,程序的一般复杂性度量如下:

  

复杂度O(f(n))表示存在c,这样在终止之前相应的图灵机步骤的数量不超过c * f(n),其中n是输入的长度。

在这个定义中,一切都被考虑在内,因为整数可能是任意大的,对它们的算术运算也会增加O(n)下的函数。

但如果我们直接编写图灵机,你的问题就不会出现了。在现实世界中,我们更喜欢抽象。虽然我们仍然计算运行程序所需的“步骤”,但我们假设某些操作需要一步。我们假设出于不同的原因:

  • 它可能类似于CPU的实际工作,其中每个32位整数加法确实是一步(并且存在实际滥用它的算法,例如“bit-verctor dominators”)。
  • 我们比较同一域中的不同算法(例如,通过测量比较次数来比较数组排序)。

在这种情况下(你的第一个编辑),如果你想要复杂化你的复杂性度量,你应该只在O下加倍函数。如果你认为现在考虑采取一步的步骤采取O(log N)步骤,那么混凝土台阶的数量增加了一个因子O(log N)。因此,总复杂度为O(N log N log N)。


关于你的第二次编辑,这是一个不同的情况。让您的算法成为O(n log N)的复杂度。但是你知道输入包含M个数字,每个log K个数字,所以`N = O(M log K)(我们需要考虑分隔符等)。这在数学上是正确的,然后将整体复杂度写为O(M * log K *(log M + log log K)),所以这里没有问题。但通常我们会抽象出不必要的细节,以找到不同算法的共同基础。