簡體   English   中英

Python中的遞歸合並排序和堆棧框架

[英]Recursive Merge sort and Stack Frames in Python

以下代碼(不是我的代碼,只是研究它)在list_原始列表(即list_ )和合並例程之間(正確)反彈。 堆棧幀的流程(即,即使如何使用Python Tutor觀看,也不清楚它們如何以及為什么返回它們的方式,這是我在下面的內容)。 有關代碼返回方式和程序遵循問題的說明。

def merge(left, right):
    if not len(left) or not len(right):
        return left or right

    result = []
    i, j = 0, 0
    while (len(result) < len(left) + len(right)):
        if left[i] < right[j]:
            result.append(left[i])
            i+= 1
        else:
            result.append(right[j])
            j+= 1
        if i == len(left) or j == len(right):
            result.extend(left[i:] or right[j:])
            break 

    return result

def mergesort(list_):
    if len(list_) < 2:
        return list_

    middle = len(list_)//2
    left = mergesort(list_[:middle])
    right = mergesort(list_[middle:])

    return merge(left, right)


list_ = [7,5,2,1,3]

print(mergesort(list_))

left的第一個遞歸調用是left (我們要對列表的左半部分進行排序,然后對左半部分的左半部分進行排序,依此類推,直到我們得到一個大小為1的列表並擊中基本情況)。 這很好。 我們從[7,5,2,1,3]轉到[7,5]到[7],然后打了基礎案例。 到現在為止還挺好。 我希望堆棧幀開始返回,但這不是真的。 我認為它返回了7,但隨后我們跳到下一組對right的遞歸調用。 5重新出現。 5出現在堆棧框架中緊接7之前,因此情況以相反的順序返回(很好)。 新參數將5分割開,並創建一個列表,從而設置基本情況並返回5。

這是很奇怪的地方:程序進入合並步驟,這是正確的。 它是如何“知道”,進一步跳過遞歸的rightleft (我給它一個完整的列表,其中大部分是不變),並跳轉到合並嗎? 而且,它如何知道在沒有顯式指令的情況下從合並返回到mergesort函數,並確切地知道在哪里提取? 誰能對此有所啟發? 傳統算法文本和大多數視頻都沒有幫助,因為它們不能解決堆棧幀。

我認為您的困惑與不了解每個堆棧框架都有自己的執行點有關。 每次調用函數時,框架的執行都會暫停,並為該函數調用創建一個新的框架。 返回時,上一幀從上次停止處開始拾取。 沒有中央位置可以“知道”下一步應該去的代碼,每個級別都自行處理。

在您描述的示例場景中,對[7, 5] mergesort [7, 5]mergesort調用首先將列表分成[7][5] ,然后依次遞歸以分別獲得leftright 當這些遞歸調用中的第二個返回時,它繼續進行到代碼的下一部分,即merge調用,這僅僅是因為這就是代碼的下一部分。

您可以在這里很清楚地看到邏輯:

left = mergesort(list_[:middle])
right = mergesort(list_[middle:])

return merge(left, right)

這告訴您,在此運行中(以及所有不影響基本情況的運行),它將遞歸兩次,然后merge

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM