繁体   English   中英

如何使这个合并排序 function 成为生成器(Python)?

[英]How do I make this Merge Sort function a generator (Python)?

所以我了解如何在 Python 3 中进行合并排序算法,这是我下面用于实现 function 的代码:

def x(arr):
    for i in mergeSort(arr):
        yield from i

def mergeSort(arr):
    if len(arr) > 1:
        middle = len(arr) // 2
        left = arr[:middle]
        right = arr[middle:]

        mergeSort(left)
        mergeSort(right)

        a = 0
        b = 0
        c = 0

        while a < len(left) and b < len(right):
            if left[a] < right[b]:
                arr[c] = left[a]
                a += 1
            else:
                arr[c] = right[b]
                b += 1
            c += 1

        while a < len(left):
            arr[c] = left[a]
            a += 1
            c += 1

        while b < len(right):
            arr[c] = right[b]
            b += 1
            c += 1

for i in mergeSort([6,3,8,7,4,1,2,9,5,0]):
    print(i)

它的要点是 function 返回最后排序的数组。 但是,我正在尝试构建一个排序可视化器,为此,我需要让这个 function 在进行更改时产生数组,以便您可以看到条形开关 -所以我需要将其设为 generator ,但所有尝试我已经这样做了,但没有奏效。 如何修改我的代码以使此 function 成为生成器?

谢谢。

首先,您需要确保深度递归执行实际上可以报告整个列表的 state。 使用您当前的设置是不可能的,因为递归 function 只能看到数组的一小部分。

因此,为了解决这种情况,不要通过递归调用传递切片,而是传递开始/结束索引,从而为所有 function 执行上下文提供对相同arr的访问权限。

然后你可以在每次合并后yield arr 进行递归调用的代码应使用yield from

我修改了您的代码只是为了应用上述想法:

def mergeSort(arr):
    # arr is a unique list that all levels in the recursion tree can access:

    def mergeSortRec(start, end):  # separate function that can take start/end indices
        if end - start > 1:
            middle = (start + end) // 2

            yield from mergeSortRec(start, middle)  # don't provide slice, but index range
            yield from mergeSortRec(middle, end)
            left = arr[start:middle]
            right  = arr[middle:end]

            a = 0
            b = 0
            c = start

            while a < len(left) and b < len(right):
                if left[a] < right[b]:
                    arr[c] = left[a]
                    a += 1
                else:
                    arr[c] = right[b]
                    b += 1
                c += 1

            while a < len(left):
                arr[c] = left[a]
                a += 1
                c += 1

            while b < len(right):
                arr[c] = right[b]
                b += 1
                c += 1
            
            yield arr

    yield from mergeSortRec(0, len(arr))  # call inner function with start/end arguments

for i in mergeSort([6,3,8,7,4,1,2,9,5,0]):
    print(i)

对于示例列表,output 如下:

[3, 6, 8, 7, 4, 1, 2, 9, 5, 0]
[3, 6, 8, 4, 7, 1, 2, 9, 5, 0]
[3, 6, 4, 7, 8, 1, 2, 9, 5, 0]
[3, 4, 6, 7, 8, 1, 2, 9, 5, 0]
[3, 4, 6, 7, 8, 1, 2, 9, 5, 0]
[3, 4, 6, 7, 8, 1, 2, 9, 0, 5]
[3, 4, 6, 7, 8, 1, 2, 0, 5, 9]
[3, 4, 6, 7, 8, 0, 1, 2, 5, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

您可以决定还产生开始/结束索引,以便迭代器的使用者知道算法在哪里操作列表。 所以然后改变:

        yield arr

至:

        yield arr, start, end

随着这一变化,output 变为:

([3, 6, 8, 7, 4, 1, 2, 9, 5, 0], 0, 2)
([3, 6, 8, 4, 7, 1, 2, 9, 5, 0], 3, 5)
([3, 6, 4, 7, 8, 1, 2, 9, 5, 0], 2, 5)
([3, 4, 6, 7, 8, 1, 2, 9, 5, 0], 0, 5)
([3, 4, 6, 7, 8, 1, 2, 9, 5, 0], 5, 7)
([3, 4, 6, 7, 8, 1, 2, 9, 0, 5], 8, 10)
([3, 4, 6, 7, 8, 1, 2, 0, 5, 9], 7, 10)
([3, 4, 6, 7, 8, 0, 1, 2, 5, 9], 5, 10)
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0, 10)

也许是这样的:

def x(arr):
    for i in mergeSort(arr):
        yield i

def mergeSort(arr):
    if len(arr) > 1:
        middle = len(arr) // 2
        left = arr[:middle]
        right = arr[middle:]

        mergeSort(left)
        mergeSort(right)

        a = 0
        b = 0
        c = 0

        while a < len(left) and b < len(right):
            if left[a] < right[b]:
                arr[c] = left[a]
                a += 1
            else:
                arr[c] = right[b]
                b += 1
            c += 1

        while a < len(left):
            arr[c] = left[a]
            a += 1
            c += 1

        while b < len(right):
            arr[c] = right[b]
            b += 1
            c += 1
        return arr

# Entry point
generator = x([6,3,8,7,4,1,2,9,5,0])
print(next(generator)) # prints 0
print(next(generator)) # prints 1

# print the remaining elements
for i in generator:
  print(i)

Output:

0
1
2
3
4
5
6
7
8
9

请注意,您可以使用的合并排序的较短递归实现可能如下:

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

    less = []
    equal = []
    greater = []
    
    n = int(len(mylist)/2)
    pivot = mylist[n]

    for x in mylist:
      if x < pivot:
          less.append(x)
      elif x == pivot:
          equal.append(x)
      elif x > pivot:
          greater.append(x)

    return merge_sort(less) + equal + merge_sort(greater)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM