我正在尝试评估对数字列表进行排序的两个Python方法的性能。两者的时间复杂度似乎均为n ^ 2,但经验数据表明,其中一个的性能优于另一个。有什么原因吗?
我写了两种方法,一种是使用嵌套的for循环,另一种是找到一个最大值,然后将该最大值迭代添加到新列表中(并从旧列表中删除)。
方法1:
def mysort1(l):
i = 0
j = 1
for i in range(0,len(l)-1):
for j in range(i,len(l)):
if l[i] > l[j]:
tmp = l[j]
l[j] = l[i]
l[i] = tmp
return l
方法2:
def mysort2(l):
nl = []
for i in range(0,len(l)):
m = max(l)
nl.insert(0, m)
l.remove(m)
return nl
两者都以相反的顺序用10000个数字进行了测试。使用配置文件时,方法1大约需要8秒(10000次以上的调用),方法2仅需要0.6秒(30000次以上的调用)。即使方法2的时间复杂度似乎相同,为什么方法2的性能比方法1更好的任何原因?
答案 0 :(得分:3)
基本上,正如评论所建议的那样,它归结为Python在C中的主要实现。This answer指出,真正的原因是C的对应物,即列表操作{{1 }}等,由于许多人优化了代码,因此它比Python的实现要快得多,并且在这种情况下,C的运行速度通常比Python快。
Here是对“为什么Python程序通常比用C或C ++编写的等效程序慢的问题?”的另一个答案。
从答案:
在内部,Python代码执行速度较慢的原因是因为代码是在运行时解释的,而不是在编译时编译为本机代码。
其他解释语言(例如Java字节码和.NET字节码)的运行速度比Python快,因为标准发行版包含一个JIT编译器,该JIT编译器在运行时将字节码编译为本机代码。 CPython还没有JIT编译器的原因是因为Python的动态特性使其难以编写。正在编写一个更快的Python运行时的工作正在进行中,因此您应该期望将来能减少性能差距,但是在标准Python发行版包含功能强大的JIT编译器之前,可能还需要一段时间。
答案 1 :(得分:2)
Python不会给出有关时间复杂度的#@&^ (当然可以,但是...)
被解释为动态类型语言的Python在类型检查和运行时“编译”上有很多时间开销。例如,在您的第一种方法中,它必须在每次迭代中至少检查六次dt <- structure(list(C = c("8.5%", "13.13%", "15.75%", "7.5%"), P = c(100.9063,
105.9961, 112.4102, 101.2188)), class = "data.frame", row.names = c(NA,
-4L))
的类型(在为列表建立索引时)。
因此,我认为处理时间的差异是因为i
是经过优化的,并且(如您可能使用的CPython解释器)基本上是C函数(以及max
和.insert
方法)。
答案 2 :(得分:1)
这两个函数在N = len(l)
中具有二次运行时间,但这仅意味着第一个函数所花费的时间渐近地由某个c_1 * N^2
限定,第二个函数所花费的时间由某个c_2 * N^2
所限定。
c_1
和c_2
的值可以有很大的不同。在您的情况下,第二个函数可以在Python的实现中的max
,insert
和remove
中执行内部循环,该循环被编译为本地机器代码并针对特定目的进行了优化。必须以解释的Python字节码执行内部循环。后者通常会花费更多时间。
在谈论时间复杂度时,通常会从讨论中删除该前置因子(例如,使用big-O表示法),因为它取决于各个操作花费的特定时间,而N^2
行为对于该算法的任何实现都是通用的
此外,在有限的N
复杂度理论中,根本没有论据。对于前10^100
或N
的任何值,时间复杂度严格较低的算法的性能可能会比其他算法差(尽管这在您的特定情况下不是问题)。