问题描述
我已经用 python 编写了 2 个最近邻算法,我必须通过 O(n) 和 Θ(n) 分析运行时复杂度。 所以我尝试了几个样本,但我不明白为什么我的一个算法比另一个更快。
所以这是我的重复最近邻 (RNN) 算法代码:
def repeated_nn_tsp(cities):
return shortest_tour(nn_tsp(cities,start) for start in cities)
def shortest_tour(self,tours):
return min(tours,key=self.tour_length)
nn_tsp 的运行时复杂度为 O(n^2),每个起点都会创建一个新的 NN Tour。通过所有 NN 之旅,我必须找到最好的旅程。 这就是为什么我认为 RNN 的时间复杂度必须是 T(n)=O(n^3) 和 T(n)=Θ(n^3)。
所以这是我的更改最近邻 (ANN) 算法的代码:
def alter_tour(tour):
original_length = tour_length(tour)
for (start,end) in all_segments(len(tour)):
reverse_segment_if_better(tour,start,end)
if tour_length(tour) < original_length:
return alter_tour(tour)
return tour
def all_segments(N):
return [(start,start + length) for length in range(N,2-1,-1) for start in range(N - length + 1)]
def reverse_segment_if_better(tour,i,j):
A,B,C,D = tour[i-1],tour[i],tour[j-1],tour[j % len(tour)]
if distance(A,B) + distance(C,D) > distance(A,C) + distance(B,D):
tour[i:j] = reversed(tour[i:j])
all_segments 的时间复杂度应该是 T(n) = O(1/2 * n^2 - 0.5n) -> O(n^2) 并创建 n^2 个元素。 在通过 all_segments(通过 n^2 个元素)的循环中,我调用函数 reverse_segment_if_better。我将使用python的反向方法,这会导致时间复杂度为O(n)。 这就是为什么我认为循环的时间复杂度必须是 O(n^3)。当有更好的游览时,该函数将调用自己递归。我认为改变后的 NN 的结果的时间复杂度为 O(n^4)。是吗?
但现在我们来解决我的问题:我的评估在 100 个城市上运行了 100 次代码,结果表明 ANN 平均比 RNN 快,这与我预期的运行时复杂性相反。 (对于 1x 100 个城市,RNN 需要 4.829 秒,而 ANN 只需要 0.877 秒。)
那么我哪里做错了?
提前致谢!
解决方法
首先我必须说时间复杂度和大 o 符号并不总是很重要,一个算法可能有一个“更好”的运行时函数,但仍然会比预期运行得慢,或者比另一个函数慢运行时函数,在您的情况下,很难确定最坏的情况是什么来提供算法,我们不能保证您已经这样做了!也许这些案例对 ANN
算法来说是“令人愉快的”,而另一个案例却卡在了某个地方..?这就是为什么仅依赖我们计算的运行时间函数并不总是 100% 正确的原因。
我想说的是,您很可能没有故意在计算中犯错误,因为它们是很难动态分析的函数,或者 What kind of input would be the worst,for example
至于“为什么?”:
-
说到个人实际运行时间(如您举的 0.877 秒的示例),归结为我们自己的机器,每台计算机背后都有自己的运行硬件,并非所有计算机都生来相同.
-
其次,当我们谈论运行时间复杂度时,我们会像使用
all_segments
函数一样删除低项值,您可以看到您甚至删除了一个负项,这在理论上会对我们有所帮助减少“操作”的数量。 -
在很多情况下,有些代码效率不高,我们只在满足特定条件时才执行,从而减少了运行时间。
-
最后也是最重要的是当我们谈论分类时 算法转换成我们正在谈论的
O(n)
或O(nlogn)
等集合 渐近函数,我们需要放眼大局,看看 当我们向算法提供大量数据时会发生什么 我假设你没有检查,因为正如你写的,你只跑了 100 个城市。那可能 如果我们看看数以百万计的城市,情况会有所不同。
对于您的代码,我可以注意到多个部分可能会导致运行时间出现这种“奇怪”差异。首先,在 ANN
代码中,更具体地说,在 reverse_segment_if_better
函数中,我们并不总是反转列表,只有当某个语句被评估为真值时。我们无法确定您给算法提供了什么样的输入,因此我只能想象它符合第二种算法。
此外,可能是我遗漏了一些东西(作为函数 reverse_segment_if_better
/ 我们无法查看函数 tour_length
或 distance
)但我不明白你是怎么想出来的以 O(n^4)
结尾,它似乎在执行 O(n^3)
:
all_segments- no doubt it is O(n) - returning ~n/2 values
棘手的部分是分析 reverse_segment_if_better
和 alter_tour
- 反转只发生在 i:j
因此严格地说它有 O(n)
并不正确 - 因为我们没有反转 整个游览(至少,不是针对 start,end
的每个值。
可以肯定地说,可能是没有渐进检查非常大的数字的情况,您给了一个输入并且对这个特定算法很友好,或者 T(n)
的最终形式不够严格.