英文:
Complexity does not match the actual growth of the runtime?
问题
我已经做了一段时间的家庭作业,但在我认为的渐近复杂度和运行时间结果之间存在着巨大的差异。
下面是程序运行时间的表格。
| 输入规模 | 运行时间(秒) |
|---------------------|-------------------------|
| 10000 | 0.040533803 |
|---------------------|-------------------------|
| 20000 | 0.154712122 |
|---------------------|-------------------------|
| 30000 | 0.330814060 |
|---------------------|-------------------------|
| 40000 | 0.603440983 |
|---------------------|-------------------------|
| 50000 | 0.969272780 |
|---------------------|-------------------------|
| 60000 | 1.448454467 |
string = "";
newLetter = "a";
for (int i = 500; i < n; i++) {
string = string + newLetter;
}
return string
除了我可能错了之外,为什么算法的复杂度和运行时间增长之间会存在差异呢?
从运行时间的结果来看,该程序的时间复杂度似乎是 O(n^2)。将输入规模加倍似乎会使运行时间增加4倍,这会暗示二次函数?
但是从程序本身来看,我有99.9%的把握时间复杂度实际上是 O(n)。
除了我认为的错误之外,是否有其他原因导致了这种差异呢?有没有可能运行时间的结果实际上是线性的?
我对这种差异的最佳猜测是,for循环使得下一次迭代变慢(从程序的角度来看,我认为Java编译器必须迭代每个额外的newLetter),但这仍然是线性的,对吗?这并不是嵌套的for循环。
英文:
I've been doing a homework sheet for a while now, and there is a massive discrepancy between what I think the asymptomatic complexity is and what the runtime result suggests.
Below is a table for the runtime for the program.
| Input Size | Runtime (Seconds) |
|---------------------|-------------------------|
| 10000 | 0.040533803 |
|---------------------|-------------------------|
| 20000 | 0.154712122 |
|---------------------|-------------------------|
| 30000 | 0.330814060 |
|---------------------|-------------------------|
| 40000 | 0.603440983 |
|---------------------|-------------------------|
| 50000 | 0.969272780 |
|---------------------|-------------------------|
| 60000 | 1.448454467 |
string = "";
newLetter = "a";
for (int i = 500; i < n; i++) {
string = string + newLetter;
}
return string
Why would there be a discrepancy between the complexity of the algorithm and the growth of the runtime apart from me being wrong?
From the runtime results, it looks like the program has a time complexity of O(n<sup>2</sup>). Doubling the input size seems to increase the runtime by a factor of 4, which would suggest a quadratic function?
But looking at the program itself, I'm 99.9% certain that the time complexity is actually O(n).
Is it possible that there's an extraneous reason for this discrepancy? Is there any possibility that the runtime results are indeed linear?
My best guess for this discrepancy is that the for loop makes the next iteration slower (which, looking at the program makes sense as I think the Java compiler would have to iterate every additional newLetter given) but that would still be linear no? It's not a nested for loop.
答案1
得分: 3
你编写的代码实际上在时间复杂度上是可以运行的,具体来说是 Θ(n2)。原因与代码的这部分有关:
string = string + newLetter;
在这里,你的意图是想说“请将一个新字符追加到这个字符串的末尾。”然而,Java 实际上执行的操作是:
- 计算表达式
string + newLetter
。这将创建一个全新的字符串,其中包含了将string
的全部内容复制过来,然后将newLetter
追加到这个新字符串的末尾。 - 将结果赋值给
string
。
问题在于,步骤(1)的执行时间随着字符串的长度增加而逐渐变长,因为所有字符都必须被复制过去。特别地,如果 string
的长度为 k
,那么步骤(1)需要时间 Θ(k),因为需要复制 k 个字符。由于 string
的长度与当前循环迭代索引匹配,这意味着所需的工作量为
> Θ(1 + 2 + 3 + ... + n)
>
> = Θ(n(n+1) / 2)
>
> = Θ(n2),
这就是你所看到的图形的原因。
你可以通过使用 StringBuilder
而不是 String
来加快速度,以组装更大的字符串。它在进行操作时不会创建所有中间副本,而是维护一个可以根据需要增长的内部数组。
英文:
The code you've written actually does run in time Θ(n<sup>2</sup>). The reason has to do with this part of the code:
string = string + newLetter;
Here, your intent is to say "please append a new character to the end of this string." However, what Java actually does is the following:
- Evaluate the expression
string + newLetter
. This makes a brand-new string formed by copying the full contents ofstring
, then appendingnewLetter
to the end of that new string. - Assign the result to
string
.
The issue here is that step (1) takes longer and longer to execute the longer the string is, since all the characters have to be copied over. In particular, if string
has length k
, then step (1) takes time Θ(k) because k characters must be copied. Since the length of string
matches the current loop iteration index, this means the work done is
> Θ(1 + 2 + 3 + ... + n)
>
> = Θ(n(n+1) / 2)
>
> = Θ(n<sup>2</sup>),
which is why you're seeing the plot you're seeing.
You can speed this up by using StringBuilder
rather than String
to assemble the larger string. It doesn't make all the intermediary copies as it goes, and instead maintains an internal array that can grow as needed.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论