使MergeSort更高效

时间:2017-08-30 12:54:25

标签: python sorting mergesort

我正在处理一个黑客问题:https://www.hackerrank.com/challenges/big-sorting

并在Python中编写了MergeSort的实现。该算法工作正常,但我在一些较大的输入测试中得到超时错误。由于我不是Python专家,任何人都可以建议如何提高我的代码效率吗?

unsorted = map(int, unsorted) # Unsorted is provided as an input, an array of strings


def mergeSort(list):
    s = len(list)

    if s == 1:
        return list

    if s == 2:
        if list[0] < list[1]:
            return list
        return [list[1], list[0]]

    listA = mergeSort(list[:s / 2])
    listB = mergeSort(list[s / 2:])

    r = []

    while len(listA) > 0 or len(listB) > 0:
        if len(listA) == 0:
            r = r + listB
            return r

        if len(listB) == 0:
            r = r + listA
            return r

        if listA[0] < listB[0]:
            r.append(listA.pop(0))
        else:
            r.append(listB.pop(0))


list = mergeSort(unsorted)
for n in list:
    print n

3 个答案:

答案 0 :(得分:1)

针对1到10000之间的100000个随机数列表运行脚本,这给我分析了一下:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    3.687    3.687 <string>:1(<module>)
 131071/1    1.457    0.000    3.687    3.687 \Test\untitled4.py:8(mergeSort)
  1502009    1.903    0.000    1.903    0.000 {method 'pop' of 'list' objects}
  4833703    0.217    0.000    0.217    0.000 {len}
  1502009    0.110    0.000    0.110    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

从中您可以看到大部分时间花在pop()len()以及函数调用上。例如,可以通过使用较低的指针来消除pop(0)。 关于python中mergesort算法的类似优化有很多问题,所以请尝试在类似问题的答案中应用优化。

答案 1 :(得分:0)

  1. 您通过切片继续复制子列表的事实(例如 list[:s / 2])使用的内存比你的内存多得多 已实施merge-sort以运行“in-place”。
  2. 可能是合并排序太慢,有些算法会有一些限制,运行得更快,例如counting sortradix sort

答案 2 :(得分:0)

其他人也做过类似的挑战:

Recursive algorithm works without return statement? (Runs really fast)

对于此挑战,字符串没有前导零并且将被视为整数。较长的字符串大于较短的字符串。需要首先进行长度比较,并且只有长度相等才能比较字符串。

这可以通过辅助数组的一次性分配进一步改进,aux = [none] * n,其中n是行数(main()需要计算行并将n作为参数传递到排序功能)。如果使用自顶向下合并排序,可以使用一对相互递归的函数来避免数据复制(在这种情况下,我假设&#34;数据&#34;实际上相当于指向字符串的指针数组,并且字符串永远不会被排序)。一个函数以原始数组中的已排序子数组结束,另一个函数以辅助数组中的已排序子数组结束。每个函数调用另一个函数两次,一次为左半部分,一次为右半部分,然后合并两半。在排序数据最终在辅助数组中并且大小为1的特殊情况下,将单个元素从原始数据复制到辅助数组。

自下而上合并排序会更快一些,因为它会跳过用于生成n-1对索引的所有递归,并通过将n个元素的数组视为每个1个元素的n个子数组开始,然后使用迭代来操纵索引。它的速度并不快,因为大部分时间都花在了合并函数上,并且合并函数对于自上而下和自下而上的合并排序都是相同的。与优化的自顶向下合并排序类似,通过基于合并传递更改合并方向来避免复制。合并传递的数量是根据n预先确定的,如果它是奇数次传递,第一次传递可以交换元素对,留下偶数个合并传递来做到这一点排序后的数据最终会在原始数组中结束。

这个挑战似乎是在C中实现的,因为它提供了一个C片段。 python实现会明显变慢。