Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 替代合并排序的效率?_Python_Algorithm_Performance_Sorting_Data Structures - Fatal编程技术网

Python 替代合并排序的效率?

Python 替代合并排序的效率?,python,algorithm,performance,sorting,data-structures,Python,Algorithm,Performance,Sorting,Data Structures,我正在学习合并排序和我看过的许多教程,它们是通过替换原始数组的值来合并的,就像这样。我想知道我的替代实现是否正确。我只见过一个人做同样的事。我的实现返回排序数组,如下所示: def mergesort(arr): if len(arr) == 1: return arr mid = len(arr) // 2 left_arr = arr[:mid] right_arr = arr[mid:] return merge(mergesort

我正在学习合并排序和我看过的许多教程,它们是通过替换原始数组的值来合并的,就像这样。我想知道我的替代实现是否正确。我只见过一个人做同样的事。我的实现返回排序数组,如下所示:

def mergesort(arr):
    if len(arr) == 1:
        return arr
    mid = len(arr) // 2
    left_arr = arr[:mid]
    right_arr = arr[mid:]

    return merge(mergesort(left_arr), mergesort(right_arr))

def merge(left_arr, right_arr):
    merged_arr = [] # put merge of left_arr & right_arr here
    i,j = 0, 0 # indices for left_arr & right_arr

    while i < len(left_arr) and j < len(right_arr):
        if left_arr[i] < right_arr[j]:
            merged_arr.append(left_arr[i])
            i += 1
        else:
            merged_arr.append(right_arr[j])
            j += 1

    # add remaining elements to resulting arrray
    merged_arr.extend(left_arr[i:]) 
    merged_arr.extend(right_arr[j:])
    return merged_arr


arr = [12, 11, 13, 5, 6, 7]
sorted_arr = mergesort(arr)
print(sorted_arr)
# Output: [5, 6, 7, 11, 12, 13]
def合并排序(arr):
如果len(arr)==1:
返回arr
mid=len(arr)//2
左对齐=对齐[:中间]
右_arr=arr[mid:]
返回合并(合并排序(左对齐),合并排序(右对齐))
def合并(左对齐,右对齐):
合并的_arr=[]将左_arr和右_arr的合并放在这里
i、 j=0,0#左_arr和右_arr的索引
当i

对我来说,这是一种更直观的合并排序方法。这个实现是否破坏了合并排序应该是什么?在速度方面还是在空间方面效率较低(除了创建结果数组之外)?

Python的家伙会为列表的有效性而烦恼吗:)

为了实现经典合并排序实现的最佳速度,在编译语言中,应该只提供一次辅助内存块以最小化分配操作(当算术非常简单时,内存吞吐量通常是限制阶段)


也许这种方法(将工作空间预分配为list,size=source size)在Python实现中也可能有用。

如果我们考虑使用
O(n)
额外内存的合并排序,那么您的实现似乎是正确的,但效率低下。让我们来看看以下几行:

def mergesort(arr):
    ...
    mid = len(arr) // 2
    left_arr = arr[:mid]
    right_arr = arr[mid:]
实际上,每次调用
mergesort()
时,您都会创建两个新数组,然后从原始
arr
复制元素。这是堆上的两个额外内存分配和
O(n)
copies。通常,由于复杂的分配器算法,堆内存分配非常缓慢

去父亲吧,让我们考虑一下这条线:

merged_arr.append(left_arr[i])  # or similar merged_arr.append(left_arr[j])
这里再次发生了大量内存分配,因为您使用了动态分配的数组(也称为列表)

因此,合并排序最有效的方法是在一开始就分配一个原始数组大小的额外数组,然后使用其部分获得临时结果

def mergesort(arr):
    mergesort_helper(arr[:], arr, 0, len(arr))

def mergesort_helper(arr, aux, l, r):
    """ sorts from arr to aux """
    if l >= r - 1:
        return

    m = l + (r - l) // 2
    mergesort_helper(aux, arr, l, m)
    mergesort_helper(aux, arr, m, r)
    merge(arr, aux, l, m, r)

def merge(arr, aux, l, m, r):
    i = l
    j = m
    k = l
    while i < m and j < r:
        if arr[i] < arr[j]:
            aux[k] = arr[i]
            i += 1
        else:
            aux[k] = arr[j]
            j += 1
        k += 1

    while i < m:
        aux[k] = arr[i]
        i += 1
        k += 1

    while j < r:
        aux[k] = arr[j]
        j += 1
        k += 1

import random

def testit():
    for _ in range(1000):
        n = random.randint(1, 1000)
        arr = [0]*n
        for i in range(n):
            arr[i] = random.randint(0, 100)

        sarr = sorted(arr)
        mergesort(arr)
        assert sarr == arr

testit()
def合并排序(arr):
合并排序辅助程序(arr[:],arr,0,len(arr))
def合并排序辅助程序(arr、aux、l、r):
“”“从arr排序到aux”“”
如果l>=r-1:
返回
m=l+(r-l)//2
合并排序辅助程序(辅助、arr、l、m)
合并排序辅助程序(辅助、arr、m、r)
合并(arr、aux、l、m、r)
def合并(arr、aux、l、m、r):
i=l
j=m
k=l
当i
合并排序的实现是正确的

正如您所指出的,您正在使用一个额外的数组来合并结果。使用此替代数组,将空间复杂度添加为O(n)

但是,您提到的第一个链接: 还增加了相同的空间复杂性:

/* create temp arrays */
int L[n1], R[n2]; 

注意:如果您感兴趣,请查看

我认为这是合并排序的一个很好的实现,因为评估算法的复杂性是合并排序复杂性的一部分,即:给定n个要排序的元素数

T(n) = 2T (n / 2) + n

合并排序通常使用O(n)空间,对吗?所以你是说这个替代版本在技术上仍然是O(n),但效率要低得多?你能给我指出一个教程吗?它确实“一开始就分配一个原始数组大小的额外数组,然后使用它的部分获得临时结果。”?合并排序也可以在不使用额外内存的情况下就地实现,请选中此项。@Donovankeing请检查更新的答案,我添加了一个带有aux数组的示例。@IvanVelichko虽然您可以使用恒定的额外内存实现合并排序,但这样做并不是特别有效。随着
n
的增长,在固定大小的辅助数组中交换内容的时间开始支配运行时间。@JimMischel我调整了代码,现在它没有这个额外的复制循环。然而,这个技巧需要在排序入口点的主数组和辅助数组之间进行切换。我的基本上是L[n1]、R[n2]和合并的空间,因为我创建了左数组和右数组。就大O而言,您的空间成本将是:O(n/2)+O(n/2)+O(n)=O(n)你是在建议就地合并排序吗?不是。就地合并排序比较慢,主要是理论上比较有趣。但为算法工作提供即时空间是常见的技术。也许使用Python不会获得显著的收益,但它可能会被检查。