如何提高python中的合并排序速度

时间:2015-10-21 18:56:08

标签: python algorithm sorting python-3.x optimization

是的,这是家庭作业,但我最终用Java完成它只是为了完成它,但现在python实现困扰着我。我很确定我已经正确实现了它,但它需要的时间比它应该的长。在300万输入上,它可以在25到32秒内完成。我假设它与我拼接的方式有关,并附加到列表中。我在这里有源代码,如果你看到任何内容,请告诉我。

def merge_sort(seq):
    if len(seq) == 1:
        return seq
    left = merge_sort(seq[:len(seq) // 2])
    right = merge_sort(seq[len(seq) // 2:])

    return merge(left, right)


def merge(left, right):
    result = []
    left_count = 0
    right_count = 0
    while len(left) > left_count and len(right) > right_count:
        if left[left_count] > right[right_count]:
            result.append(right[right_count])
            right_count += 1
        else:
            result.append(left[left_count])
            left_count += 1

    while len(left) > left_count:
        result.append(left[left_count])
        left_count += 1

    while len(right) > right_count:
        steps += 1
        result.append(right[right_count])
        right_count += 1

    return result

3 个答案:

答案 0 :(得分:0)

我认为你是对的。切片会创建一个包含切片元素的新列表。这必然是一项代价高昂的操作。

在Java中,没有一般的切片功能。但是,如果您使用List.subList将返回原始视图而不是副本,我认为会更快。就地数组操作会更快。

答案 1 :(得分:0)

使用

while True:

而不是

while len(left) > left_count and len(right) > right_count:

让我快40-45%:

def merge(left, right):
    result = []
    left_count = 0
    right_count = 0
    try:
        while True:
            if left[left_count] > right[right_count]:
                result.append(right[right_count])
                right_count += 1
            else:
                result.append(left[left_count])
                left_count += 1
    except:
        return result + left[left_count:] + right[right_count:]

最后一行似乎没有让它更快,但我更喜欢它。

答案 2 :(得分:0)

来自Rishav Kundu链接的先前帖子:

您可以在顶级调用mergesort中初始化整个结果列表:

result = [0]*len(x)   # replace 0 with a suitable default element if necessary. 
                      # or just copy x (result = x[:])

然后,对于递归调用,您可以使用辅助函数,而不是将子列表传递给x。底层调用从x读取其值并直接写入result

为此,seq数组的参数需要是对seq和辅助数组的引用。

您还可以添加参数以跟踪要合并的方向,以避免复制步骤。 C示例使用mtoa标志,表示从b合并到a(如果为false,则表示将a合并到b)。在我的系统上,英特尔2600K 3.4ghz,此代码在大约0.36秒内对400万个伪随机32位无符号整数进行排序,在大约1.6秒内对1600万进行排序。

void TopDownMergeSort(int seq[], size_t n)
{
int * b;
    if(n < 2)
        return;
    b = malloc(n * sizeof(seq[0]));
    TopDownSplitMerge(seq, b, 0, n, true);
    free(b);
}

void TopDownSplitMerge(int a[], int b[], size_t ll, size_t ee, bool mtoa)
{
size_t rr;
    if ((ee - ll) == 1){                    // if size == 1
        if(!mtoa)                           //  copy to b if merging a to b
            b[ll] = a[ll];
        return;
    }
    rr = (ll + ee)>>1;                      // midpoint, start of right half
    TopDownSplitMerge(a, b, ll, rr, !mtoa);
    TopDownSplitMerge(a, b, rr, ee, !mtoa);
    if(mtoa)                                // if merging to a, merge b to a
        Merge(b, a, ll, rr, ee);
    else                                    // else merge a to b
        Merge(a, b, ll, rr, ee);
}

另一种选择是使用自下而上的合并排序,它会跳过递归步骤,只是开始合并甚至是奇数运行的运行,初始运行大小为1.

相关问题