如何解决Python代码通过递归查找最大值
我对在列表中找到最大值的Python代码有疑问。功能代码如下:
def large(x):
if len(x) == 1:
return x.pop(0)
else:
temp = x.pop(0)
previous = large(x)
if previous >= temp:
return previous
else:
return temp
但是在此之前,我尝试过:
def large(x):
if len(x) == 1:
return x.pop(0)
else:
temp = x.pop(0)
if large(x) >= temp:
return large(x)
else:
return temp
它将返回错误消息为:
<ipython-input-74-dd8676a7c4e6> in large(x)
3 return x.pop(0)
4 else:
----> 5 temp = x.pop(0)
6 if large(x) >= temp:
7 return large(x)
IndexError: pop from empty list
玩具数据为:
inputlist = [6,1,3,2,4,5,6]
large(inputlist)
谢谢您的帮助。我找不到此错误的主要原因。对于我来说,这两个代码是完全相同的。
解决方法
问题
if large(x) >= temp:
return large(x)
是您最终多次调用large(x)
(因此也叫pop
),这会从列表中删除元素。
就个人而言,我会比使用pop
之类的变异函数更喜欢这种样式。
def large(x):
if len(x) == 1:
return x[0]
remainder = large(x[1:])
return x[0] if x[0] > remainder else remainder
,
与OneCricketeer相同的解决方案 但不必在每次递归调用时都无需创建列表切片。 它还处理一个空列表。
def large(x):
def rec(y):
try:
v = next(y)
except StopIteration:
return None
r = rec(y)
if r is None:
return v
return v if v > r else r
return rec(iter(x))
inputlist = [6,1,3,2,4,5,6]
print(large(inputlist))
print(large([]))
产生
6
None
,
这不能回答为什么原件不正确。相反,它奠定了可用于实现许多递归问题的“标准模式”。
我想知道应该如何用索引而不是弹出来消除每一轮中的元素数量?
不要“消除”这些元素:-)
许多递归友好问题通过减小每个步骤的 range 而起作用。这包括查找最大值(或任何可以表示为折叠的操作),二进制搜索,自上而下的合并排序等。许多这些问题本身都是使用数组和子问题归约的伪代码表示的通过调整每个递归调用的范围。在进行max / binary搜索时,这还可以避免对原始对象进行任何变异。
因此,递归max函数可以编写如下。请注意,这种通过工作状态的形式是尾叫友好的。尽管我发现这种形式更容易表达某些问题,但在Python中,[C]Python does not support Tail-Call Optimizations ^ 并不重要。
def my_max(lst,m=None,i=0):
# base-case: return result of work
if len(lst) == i:
return m
# Compute max through here
c = lst[i]
m = c if m is None or c > m else m
# Call recursive function increasing the index by 1.
# This is how the problem advances.
return my_max(lst,m,i + 1)
上面的示例还使用默认参数代替了辅助方法。这是一种使用递归结果的替代方法(通常是递归函数的引入方式)以及离散辅助方法。
def my_max(lst):
# Wrapper can ensure helper pre-conditions.
# In this case that is a non-Empty list per the base case check.
if not lst:
return None
return my_max_helper(lst,0)
def my_max_helper(lst,i):
# base case: last item in list returns itself
if len(lst) - 1 == i:
return lst[i]
c = lst[i]
m = my_max_helper(lst,i + 1)
return c if c > m else m
在两种情况下,临时变量都用于避免重复的表达式;尽管有时只是一种样式选择,但由于避免了额外的pop-mutation的意外副作用,这种一致性本来可以缓解原始问题。
应使用list
或支持O(1)索引查找的其他序列调用上述方法 。 特别是,“索引”方法不适合并且不能与生成器对象一起使用。还有其他答案可以解决这个问题-请当心避免使用诸如h,*t=l
或l[1:]
之类的潜在列表片段,这些片段可能导致不良的性能范围。
^ Python中有一些模块可以通过跳板模拟 TCO。
,由于这是递归练习,而不是我们在系统代码中要做的事情,因此,我将使用描述性代码而不是高效代码来做类似的事情:
def largest(array):
if array:
head,*tail = array
if tail and head < (result := largest(tail)):
return result
return head
return None
if __name__ == "__main__":
from random import choices
array = choices(range(100),k=10)
print(array,'->',largest(array))
输出
> python3 test.py
[46,67,22,23,20,30,7,87,50] -> 87
> python3 test.py
[83,77,61,53,65,68,43,44,47] -> 83
> python3 test.py
[36,99,47,93,60,56,90,44] -> 99
>
如果您确实需要有效,我建议安全这样做。具体来说,请不要公开带有特殊参数的API,以表明调用者没有使用 调用方,例如:
def my_max(lst,i=0):
因为它们可以为这些额外的参数提供值,这会使您的代码失败,并最终将其归咎于您。公开了调用者可能调用的内部函数的功能,而不是预期的功能:
def my_max(lst,i=0):
def my_max_helper(lst,i):
偶然为虚名my_max_helper()
自变量调用i
。相反,我会考虑嵌套您的函数以避免此类调用错误:
def largest(array):
def largest_recursive(array,index):
a = array[index]
if len(array) - index != 1:
if (b := largest_recursive(array,index + 1)) > a:
return b
return a
if array:
return largest_recursive(array,0)
return None
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。