我试图在我的算法中使数学正确,但我很难理解计算的“算法分析”,即f(n) = 1
或f(n) = n-1
等。
我创建了一个循环遍历排序整数数组的方法,并计算有多少个不同的整数(即{1,3,3,3,5,6,8} = 5
)。如何计算最坏情况?
基本上,代码是这样的:
int length = a.length;
int diffCount = 1; //The number of different integers
for(int i = 1; i < length; i++)
{
int b = a[i];
int c = a[i-1];
if(c>b)
throw new IllegalStateException("unsorted array");
if(c!=b)
diffCount++;
}
return diffCount;
还有一些其他的东西,但这只是为了防止像空数组这样的错误,所以我没有包含它。
这里最糟糕的情况是什么?如果条件c!=b
每次都为真?
答案 0 :(得分:4)
就运行时分析而言,如果对数组进行排序,则此算法始终为 O(n)。如果没有,它会在此之前抛出异常(但最坏的情况仍然是 O(n))。
取决于值,结果略有不同。请参阅Peter的答案,了解分支预测的解释。但我不认为这会显着影响运行时间。
答案 1 :(得分:1)
理论上,对于给定长度的数组,执行此循环所需的时间总是相同的。
我查看了分支预测是否会受到影响,在这种情况下它似乎不可能因为JIT足够聪明以消除第二个分支。
在C中,可以使用
删除分支diffCount += c != b;
可能JIT做了类似的事情。
答案 2 :(得分:1)
通常,在分析复杂性时,请关注您认为算法中最慢的操作。对于排序算法,我相信你选择比较。在您的代码中,我将选择两个数组访问:
int b = a[i];
int c = a[i-1];
甚至比较两者:
if (c != b) …
而不是diffCount++
。这意味着比较的结果并不重要,因为它总是会发生。
当然,您可以选择分析多个操作的复杂性。例如。对于排序,您可以查看元素交换以及元素比较。或者在您的情况下,您可能希望专注于diffCount++
因为您希望内存写入比比较慢得多。
我选择的操作会被a.length
次点击,这就是算法的复杂性。
如果这个选择的操作处于一个条件下,你必须选择(当寻找Big-O复杂性时)一个合理的上限限制条件可以被击中的频率。因此,在您的情况下,如果任何输入数组可能c != b
对于所有选中的元素对都是正确的,您可以假设它在您的分析中始终为真。