【问题标题】:Stooge Sort exponentially slower in Python compared to Java?与 Java 相比,Python 中的 Stooge 排序速度要慢得多?
【发布时间】:2014-03-29 18:50:36
【问题描述】:

我已经在 Python 和 Java 中实现了 stooge sort,但是随着输入大小的增加,与 Java 实现相比,Python 中的运行时间似乎呈指数增长。我知道算法在 Java 中比在 Python 中运行得更快的情况并不少见,但肯定不会慢这么多。

这是 Java 代码:

import java.util.Arrays;

public class Stooge {
    public static void main(String[] args) {
        int[] nums = new int[10000];
        for (int i = 10000; i > 0; i--) {
        nums[10000-i] = i;
        }
        stoogeSort(nums);
        System.out.println(Arrays.toString(nums));
    }

    public static void stoogeSort(int[] L) {
        stoogeSort(L, 0, L.length);
    }

    public static void stoogeSort(int[] L, int i, int j) {
        if (L[j-1] < L[i]) {
        int tmp = L[i];
        L[i] = L[j-1];
        L[j-1] = tmp;
        }
        if (j - i >= 3) {
            int t = (j - i) / 3;
            stoogeSort(L, i, j-t);
            stoogeSort(L, i+t, j);
            stoogeSort(L, i, j-t);
        }
    }
}

和等效的 Python 版本:

def main():
    nums = [i for i in range(10000, 0, -1)]
    stoogeSort(nums)
    print(nums)

def stoogeSort(L):
    stoogeSortRec(L, 0, len(L))

def stoogeSortRec(L, i, j):
    if L[j-1] < L[i]:
        tmp = L[i]
        L[i] = L[j-1]
        L[j-1] = tmp
    if j-i >= 3:
        t = (j-i) // 3
        stoogeSortRec(L, i, j-t)
        stoogeSortRec(L, i+t, j)
        stoogeSortRec(L, i, j-t)

【问题讨论】:

  • 在 Python 中交换变量时不需要临时变量:L[i], L[j-1] = L[j-1], L[i]
  • 我真的很困惑为什么你要两次调用同一个函数。 (你在第一个和最后一个调用相同的 stoogeSortRec 。)另外,与问题无关,但你不需要在 python 中使用 tmp 进行交换。 L[i], L[j-1] = L[j-1], L[i]
  • @Imagine:重复排序是Stooge Sort算法的一部分,以三个臭皮匠的名字命名。请注意,此算法甚至比冒泡排序还要慢。
  • @Daniel Roseman,我这样做只是为了更容易比较两者。不过感谢您的建议!
  • 你所说的“指数”是什么意思?您是否尝试过输入并且时间的比率随着2^n 而增长,或者您只是随机使用该术语?然而,这是一个经典的例子,JIT 产生了巨大的不同,因为它可以在对整数数组进行操作时优化大量的东西......尝试在 PyPy 中运行 python 代码。

标签: java python sorting python-3.x recursion


【解决方案1】:

你的版本是 a.py。

使用列表作为堆栈以避免递归的修改版本(b.py):

def main():
    nums = [i for i in range(5000, 0, -1)]
    stoogeSort(nums)
    print(nums)

def stoogeSort(L):
    stack = [(0, len(L))]
    while stack:
        i, j = stack.pop()

        if L[j - 1] < L[i]:
            L[i], L[j - 1] = L[j - 1], L[i]
        if j - i >= 3:
            t = (j - i) // 3
            stack.append((i, j - t))
            stack.append((i + t, j))
            stack.append((i, j - t))

次:

$ time pypy a.py >/dev/null 
real    2m1.855s
user    2m1.300s
sys     0m0.453s


$ time pypy b.py >/dev/null
real    1m33.410s
user    1m32.810s
sys     0m0.413s

连 Pypy 都不喜欢递归。

15m 后我放弃了 cpython (2 & 3)。

【讨论】:

  • 这很有用,谢谢!不过,我仍然想知道为什么递归版本与 Java 相比要慢得多。
  • 没有解释器/jit 技巧来加速非尾递归调用,所以我不知道。也许 Java 对于小操作(+,-//)和函数调用更快。
猜你喜欢
  • 2014-04-30
  • 2016-12-19
  • 2018-07-01
  • 2020-07-02
  • 2021-03-11
  • 1970-01-01
  • 2022-01-16
  • 2021-12-29
  • 2020-02-23
相关资源
最近更新 更多