【问题标题】:Comparison between two different merge sort implementations explained解释了两种不同的归并排序实现之间的比较
【发布时间】:2021-03-28 13:29:58
【问题描述】:

我的实现是这样写的:

def merge_sort(lst):
    if len(lst) < 2: return lst

    midx = len(lst) // 2

    return merge(
        merge_sort(lst[:midx]),
        merge_sort(lst[midx:])
    )

def merge(left, right):
    merged_lst = []
    while left and right:
        merged_lst.append((left.pop(0) if left[0] <= right[0] else right.pop(0)))

    merged_lst.extend(left if left else right)
    return merged_lst

然后我在网上找到了这个:

def mergeSort(alist):
    if len(alist)>1:
        mid = len(alist)//2
        lefthalf = alist[:mid]
        righthalf = alist[mid:]

        mergeSort(lefthalf)
        mergeSort(righthalf)

        i=0
        j=0
        k=0
        while i < len(lefthalf) and j < len(righthalf):
            if lefthalf[i] <= righthalf[j]:
                alist[k]=lefthalf[i]
                i=i+1
            else:
                alist[k]=righthalf[j]
                j=j+1
            k=k+1

        while i < len(lefthalf):
            alist[k]=lefthalf[i]
            i=i+1
            k=k+1

        while j < len(righthalf):
            alist[k]=righthalf[j]
            j=j+1
            k=k+1

我认为我的会更快,但会占用更多内存。然后我分析了med_lstbig_lst

med_lst = [random.random() for _ in range(100000)]
big_lst = [random.random() for _ in range(500000)]

在 Jupyter notebook 中使用这样的代码结构:

printmd(f'RAM at start: {memory_profiler.memory_usage()[0]:0.1f}MiB', color='blue')
t1 = time.time()
printmd(f'Sorting: {len(big_lst)} elements', color="blue")
merge_sort(big_lst)
t2 = time.time()
printmd(f'RAM after sorting list: {memory_profiler.memory_usage()[0]:0.1f}MiB, took {t2 - t1:0.1f}s', color='blue')

时间复杂性让我吃惊:

中等列表: merge_sort: 1.2s mergeSort:0.6s

大名单: merge_sort: 29.0s mergeSort:3.4s

这是否只是因为创建了一个新列表,或者可能是冲突或调整大小?还是我的实施/思考过程错误(新手错误 - 此答案为 0 分)?我认为我的功能仍然是0(nlogn),但是随着集合变得越来越大,您真的可以说它们是“可比的”

我没有逐行分析这一点,因为它更基础

【问题讨论】:

  • 从索引 0 弹出是 O(n),见 this.
  • 您的版本会创建大量列表并不断追加/弹出列表。改变内存中对象的大小从来都不是很快。第二个版本就地完成了,所以是纯计算,不用等待内存准备好
  • @AlexLarionov 第二个没有到位。
  • @superbrain @AlexLarinov 我认为该评论只是指merge中的结尾
  • @superbrain,是的,我的错,只是在看代码,忘记了归并排序的实际工作原理

标签: python complexity-theory mergesort


【解决方案1】:

正如@CH 在 cmets 中指出的那样,前面的 pop() 是罪魁祸首。

通过在弹出之前反转列表然后在弹出之后反转,我设法使我的实现实际上比另一个更快:

def merge(left, right):
    merged_lst = []
    if left: left.reverse()
    if right: right.reverse()
    while left and right:
        merged_lst.append((left.pop() if left[-1] <= right[-1] else right.pop()))
    if left: left.reverse()
    if right: right.reverse()
    merged_lst.extend(left if left else right)
    return merged_lst

中等列表:merge_sort:0.5s mergeSort:0.7s

大名单:merge_sort:2.6s mergeSort:4.0s

【讨论】:

  • 既然你设法解决了它,你不妨将你的答案标记为已接受。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-27
  • 2012-01-22
  • 2012-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多