我在Python中递归地实现了二进制搜索(我知道这很糟糕)并且使用以下代码得到了最大递归错误:
def bs_h(items,key,lower,upper):
if lower == upper:
return None
mid = (lower + upper) // 2
if key < items[mid]:
return bs_h(items,key, lower, mid)
else:
return bs_h(items,key,mid,upper)
def bs(items,key):
return bs_h(items,key, 0, len(items)-1)
然后我改变了我的参数和基本情况:
def bs_h(items,key,lower,upper):
if lower + 1 == upper:
return None
mid = (lower + upper) // 2
if key < items[mid]:
return bs_h(items,key, lower, mid)
else:
return bs_h(items,key,mid,upper)
def bs(items,key):
return bs_h(items,key, -1, len(items))
这可以修复错误,但我不确定原因。有人可以解释一下吗?
答案 0 :(得分:4)
每当你使用递归(它有时非常有用)时,你需要非常小心结束条件。
在运行代码期间的某个时刻,您可能会调用以下内容:
bs_h(items, key, 10, 11)
然后导致:
mid = (lower + upper) // 2
= (10 + 11) // 2
= 10
if key < items[10]:
return bs_h(items, key, 10, 10)
else:
return bs_h(items, key, 10, 11)
请注意,最后一条语句 - 它与条目调用相同。如果程序此时结束,它将始终以递归方式执行。
请务必检查您将如何逃离递归,顺便提一下,检查您的新改进版本&#34;对此。
答案 1 :(得分:2)
您的代码修改了什么:
if lower + 1 == upper:
return None
bs
的变化无关紧要(至少为了这个目的;我实际上反对它)。
可以从以下实验中观察到原因:
>>> (0+0)//2
0
>>> (0+1)//2
0
所以,一旦间隔<= 1,中间点不会改变所以它跟随你应该尽早停止,否则你将继续循环等待中点改变哪个永远不会发生
答案 2 :(得分:1)
在第print(lower, upper, mid)
个示例中的mid = (lower + upper) // 2
语句后面添加bs_h
语句并观察以下内容:
>>> bs(list(range(10)), 5)
0 9 4
4 9 6
4 6 5
5 6 5
5 6 5
... # repeats until max recursion depth.
由于(n+n)//2
和(n+n+1)//2
始终相同,因此您可以使用相同的bs_h
和lower
参数连续调用upper
。
您应该调整后续调用以消除边界条件(已经检查过)。您还需要返回索引之类的内容。以下内容匹配您想要的递归模式并返回正确的索引:
def bs_h(items,key,lower,upper):
if lower > upper:
return None
mid = (lower + upper) // 2
if key < items[mid]:
return bs_h(items,key, lower, mid-1)
elif key > items[mid]:
return bs_h(items,key,mid+1,upper)
else:
return mid #Found! return index
并测试:
>>> for i in range(10):
print(bs(list(range(10)), i))
0
1
2
3
4
5
6
7
8
9
>>> print(bs(list(range(10)), 4.5))
None
>>> print(bs(list(range(10)), 100000))
None
答案 3 :(得分:1)
mid
变量一次
找到元素!)即,
def bs_h(items,key,lower,upper):
if lower>upper:return None
mid = (lower + upper )// 2
if key < items[mid]:
return bs_h(items,key, lower, mid-1)
elif key > items[mid]:
return bs_h(items,key, mid+1, upper)
else:return mid
def bs(items,key):
return bs_h(sorted(items),key, 0, len(items)-1)