簡體   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