下面的代碼(不是我的,只是學習它)在原始列表(即list_
)上遞歸和合並例程之間反彈(正確)。堆棧框架的流程(即,他們如何以及爲什麼以他們的方式返回,目前還不清楚,即使在使用Python Tutor進行觀察時,這也是我在下面敘述的)。描述代碼如何返回以及問題如何跟隨程序。Python中的遞歸合併排序和堆棧幀
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
(我們要在列表的左半部分進行排序,然後左半邊的左半部分,等等,直到我們得到大小爲一的名單,打基地案件)。這工作正常。我們從[7,5,2,1,3]到[7,5]到[7]並打基礎案例。到現在爲止還挺好。 我期望堆棧幀開始返回,但那不是真的發生了什麼。我認爲它返回7,但是接着我們跳到right
的下一組遞歸調用。 5重新出現。 5出現在7之前的堆棧框架中,所以事情以相反的順序返回(這很好)。新參數拆分5並創建單個列表,從而設置基本情況並返回5.
下面是它變得很奇怪的地方:程序進入合併步驟,這是正確的。 它如何「知道」跳過right
或left
(我給了它一個完整的列表,其中大部分是未觸及過的)進一步遞歸併跳轉到合併?此外,它是如何知道從合併中回到mergesort函數的,而沒有明確的指示,並確切地知道在哪裏拾取?任何人都可以對此有所瞭解嗎?傳統的算法文本和大多數視頻都沒有幫助,因爲它們沒有處理堆棧幀。
這絕對是它的一部分。另外,我認爲我認爲在返回語句中有更多的終結點比真正的終點更多(即返回不會結束fxn,而是返回一個值)。它來自聽覺,「一旦你從你的功能中回報了某些東西,就是這樣!在此之後沒有其他東西可以來。」並把它帶走太多。另外,我也不知道EIP在這方面扮演的角色,這可能會有所幫助,但我喜歡你的技術不太好。 – Ryan
我認爲你引用的語句沒有錯,當你處理對同一個函數的多次遞歸調用時,這只是有點令人困惑。一個'return'結束了當前函數的執行,但是它不會結束調用者的執行(即使該調用者是進行遞歸調用的相同函數)。來電者只是從暫停的地方開始。所以如果你有六個棧幀深度,並且你敲了一個return語句,那麼第六幀就完成了,你將返回到第五個棧幀並繼續運行它的代碼。 – Blckknght