簡體   English   中英

使用遞歸在列表中找到最大值

[英]using recursion to find the maximum in a list

我正在嘗試使用遞歸在列表中找到最大的元素。 輸入必須是實際列表,左索引和右索引。

我寫了一個函數,不明白為什么它不起作用。 我畫了遞歸樹,在腦海中運行了列表示例,這很有意義,這就是為什么現在更難找到解決方案的原因! (基本上是在為自己而戰)。

我知道這很丑陋,但請嘗試忽略它。 我的想法是在每次遞歸調用時將列表分成兩半(這是必需的),而左側索引將保持為0,右側將是新的減半列表的長度減去1。

該函數的第一個調用將來自tail函數。

感謝您的幫助,我希望我不會錯過任何真正愚蠢的事情,甚至更糟的是-甚至沒有關閉! 順便說一句-不使用切片來削減列表,因為不允許我這樣做。

def max22(L,left,right):
    if len(L)==1:
        return L[0]
    a = max22([L[i] for i in range(left, (left+right)//2)], 0 , len([L[i] for i in range(left, (left+right)//2)])-1)
    b = max22([L[i] for i in range(((left+right)//2)+1, right)], 0 ,len([L[i] for i in range(left, (left+right)//2)])-1)
    return max(a,b)



def max_list22(L):
    return max22(L,0,len(L)-1)

輸入示例-對於max_list22([1,20,3]),輸出將為20。

問題在於您根本不處理空列表。 max_list22([])無限遞歸, [L[i] for i in range(((left+right)//2)+1, right)]最終產生一個空列表。

首先,為清楚起見,我建議將列表理解分配給變量,這樣您就不必每次都寫兩次。 這應該使代碼更易於調試。 您也可以對(left+right)//2值執行相同的操作。

def max22(L,left,right):
    if len(L)==1:
        return L[0]
    mid = (left+right)//2
    left_L = [L[i] for i in range(left, mid)]
    right_L = [L[i] for i in range(mid+1, right)]
    a = max22(left_L,  0 , len(left_L)-1)
    b = max22(right_L, 0 , len(left_L)-1)
    return max(a,b)

def max_list22(L):
    return max22(L,0,len(L)-1)

print max_list22([4,8,15,16,23,42])

我看到此代碼有四個問題。

  1. b =行上,第二個參數使用len(left_L)而不是len(right_L)
  2. 您缺少在left_Lright_L之間的元素。 您不應該在right_L列表理解的mid添加一個。
  3. 您缺少列表的最后一個元素。 您應該在right_Lright+1 ,而不僅僅是right
  4. 如果是偶數大小的列表,則您的mid值將減一。 例如 [1,2,3,4]應該拆分為[1,2]和[3,4],但是使用mid值,您會得到[1][2,3,4] (假設您已經在前面的要點中解決了缺少的元素問題)。

解決這些問題的方法如下:

def max22(L,left,right):
    if len(L)==1:
        return L[0]
    mid = (left+right+1)//2
    left_L = [L[i] for i in range(left, mid)]
    right_L = [L[i] for i in range(mid, right+1)]
    a = max22(left_L,  0 , len(left_L)-1)
    b = max22(right_L, 0 , len(right_L)-1)
    return max(a,b)

def max_list22(L):
    return max22(L,0,len(L)-1)

print max_list22([4,8,15,16,23,42])

如果您堅持不使用臨時變量,則它看起來像:

def max22(L,left,right):
    if len(L)==1:
        return L[0]
    a = max22([L[i] for i in range(left, (left+right+1)//2)],  0 , len([L[i] for i in range(left, (left+right+1)//2)])-1)
    b = max22([L[i] for i in range((left+right+1)//2, right+1)], 0 , len([L[i] for i in range((left+right+1)//2, right+1)])-1)
    return max(a,b)

def max_list22(L):
    return max22(L,0,len(L)-1)

print max_list22([4,8,15,16,23,42])

額外的風格提示: max22不一定需要三個參數,因為left始終為零, right始終為列表的長度減去一。

def max22(L):
    if len(L)==1:
        return L[0]
    mid = (len(L))//2
    left_L = [L[i] for i in range(0, mid)]
    right_L = [L[i] for i in range(mid, len(L))]
    a = max22(left_L)
    b = max22(right_L)
    return max(a,b)

print max22([4,8,15,16,23,42])

您的問題是您無法處理不均勻的拆分。 使用您的代碼,列表可能會變成空的,但是您也可以停止使用大小1和2而不是0和1,這更自然(因為您返回的是最大值,零大小的列表沒有最大值)。

def max22(L,left,right):

    if left == right:
        # handle size 1
        return L[left]

    if left + 1 == right:
        # handle size 2
        return max(L[left], L[right])

    # split the lists (could be uneven lists!)
    split_index = (left + right) / 2
    # solve two easier problems
    return max (max22(L, left, split_index), max22(L, split_index, right))

print max22([1,20, 3], 0, 2)

筆記:

失去對列表的理解,因為列表中有索引,所以不必創建新列表。

在處理遞歸時,您必須想到:

1-停止條件 ,在這種情況下有兩個,因為列表拆分可能不均勻,從而使遞歸在不均勻條件下停止。

2-更簡單的問題步驟 假設我可以解決一個更簡單的問題,那么我該如何解決呢? 這通常是遞歸函數的末尾。 在這種情況下,在兩個較小的(索引方式)列表上調用相同的函數。 如果您熟悉遞歸,那么它看起來很像歸納證明。

Python希望明確地完成事情。 盡管Python具有某些功能,但最好讓代碼的讀者知道您要做什么,而不是擁有龐大的單行代碼,這會使人們撓頭。

祝好運!

暫無
暫無

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

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