我正在研究算法并决定将Java程序从教科书移植到Python,因为我不喜欢Java开销,特别是对于小程序,以及作为练习。
算法本身非常简单,它只是以一种强大的方式从阵列中取出所有三元组,并计算有多少三元组总和为零(例如:[ - 2,7,-5])
public static int count(int[] a) {
int N = a.length;
int cnt = 0;
for (int i = 0; i < N; i++) {
for (int j = i+1; j < N; j++) {
for (int k = j+1; k < N; k++) {
if (a[i] + a[j] + a[k] == 0) {
cnt++;
}
}
}
}
return cnt;
}
我把它移植到:
def count(a):
cnt = 0
ln = len(a)
for i in xrange(0,ln):
for j in xrange(i + 1,ln):
for k in xrange(j + 1,ln):
if a[i] + a[j] + a[k] == 0:
cnt+=1
return cnt
现在正在测量这些功能:
java : array of 2000 elements --> 3 seconds
python : array of 2000 elements --> 2 minutes, 19 seconds
UPDATE
python (pypy) : array of 2000 elements --> 4 seconds ( :-) )
当然这不是一个好的算法,它只是在这里和教科书中展示。我以前用Java和Python做了一些编程,但是没有意识到这个巨大的差异。
问题归结为:如何克服这个问题?更具体地说:
现在我在Windows 7上使用python 2.7.3和Java 1.7 32ibts。
我知道有关于java / python性能的类似问题,但是对于python有不同的运行时环境,目前对我没有帮助。
我想知道的是,如果其中一些运行时间可以弥补这个巨大的差距并值得探索吗?
更新:
我安装了pypy,现在差异很大......
更新2:
我注意到一些非常有趣的事情:答案中的islice方法在'常规'python上更快,但在pypy上慢了很多。即便如此,无论在这个算法中使用常规循环还是islices,pypy仍然可以使用得更快
由于Bakuriu在一个注释运行时环境中的注意事项可能很重要,但对于这个算法来说,运行时环境更快,对于任何算法来说都不一定快......
答案 0 :(得分:7)
尝试使用PyPy而不是CPython运行它。它很可能会更快。
答案 1 :(得分:3)
我也用C和PHP实现了这个功能。结果如下:
PHP :23.977946043015秒
Python :19.31秒
C :0.4秒
Java :0.42秒
我们正在寻找具有不同类型系统的语言。 PHP和Python是动态类型的,而C和Java是静态类型的。
因此,PHP和Python解释器花费大量时间猜测所使用的变量的类型,因此运行速度非常慢。而在C和Java中,变量的类型(和数组的元素)是静态的,即整数,因此节省了猜测时间。显然,从上面的数字可以看出,这个猜测时间太长了。
使用PyPY,猜测时间大大减少,因为PyPY使用Just In Time(JIT)编译。这种方法非常适合猜测所用变量的类型,因此可以获得性能提升。
答案 2 :(得分:2)
正如您在开始发表的评论中已经说过的那样,除了PyPy之外,没有什么好办法让这个更快。您可以尝试islice,它会迭代“a”而不是制作新的列表或范围,这应该更快。
from itertools import islice
def count(a):
cnt = 0
for x, i in enumerate(islice(a,0, None)):
for y, j in enumerate(islice(a, x + 1, None)):
for k in islice(a, y + x + 2, None):
if i + j + k == 0:
cnt+=1
return cnt
答案 3 :(得分:0)
Python 使用标准库中的 itertools 组合,会将 for 循环移至 C。