有人可以解释为什么这会修复我的递归错误吗?

时间:2017-07-24 17:30:19

标签: python

我在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))

这可以修复错误,但我不确定原因。有人可以解释一下吗?

4 个答案:

答案 0 :(得分:4)

每当你使用递归(它有时非常有用)时,你需要非常小心结束条件。

  1. 是否会终止?
  2. 如果确实如此,会有多深?
  3. 在运行代码期间的某个时刻,您可能会调用以下内容:

    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_hlower参数连续调用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变量一次 找到元素!)
  • 检查密钥是否为&lt;或者&gt;比[item]项目忽略下一次递归搜索中的mid元素(mid-1或mid + 1)

即,

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)