递归二等分搜索以检索目标的索引

时间:2019-03-19 23:22:53

标签: python python-3.x recursion bisection

我试图用二等分算法搜索发现的索引

def bi_search(nums: List[int], find: int) -> int:
    """
    Return the index of the find 
    """
    if len(nums) == 0:
        return -1
    else:
        mid = len(nums) // 2  #testEntry
        if find == nums[mid]:
            return mid 
        if find < nums[mid]:
            sub_nums = nums[:mid]
            return bi_search(sub_nums, find)  

        if find > nums[mid]:
            sub_nums = nums[mid:]
            return bi_search(sub_nums, find) #recursive case.

但是它不能按预期工作

In [26]: bi_search(list(range(1000)), 777)                     
Out[26]: 4

它返回基本情况的中点。

我注意到可以使用bisect — Array bisection algorithm — Python 3.7.3rc1 documentation

中的迭代方法来检索正确的索引

是否可以在递归解决方案中获得正确的索引?

1 个答案:

答案 0 :(得分:1)

如果在函数中添加print()语句并使用一个较小的示例,则会看到问题:

def bi_search(nums, find):
    print((nums, find))
    ...

print(bi_search(list(range(10)), 7))

输出:

([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 7)   # Looks good.
([5, 6, 7, 8, 9], 7)                  # Also good.
2                                     # Doh!

问题是您要返回的是最后检查的列表中的索引,而不是初始列表的索引。为了使您的方法可行,您需要通过递归调用传递更多信息-这很棘手。

另一种方法是传递每个呼叫的完整列表,然后随即调整搜索上下限。这还具有避免每次调用都创建新列表的优点。例如:

def bi_search(nums, find, i = None, j = None):
    # Setup.
    N = len(nums)
    if i is None:
        i = 0
        j = N - 1
    # Base case for failure.
    if j < i:
        return None
    # Success or recurse.
    mid = (i + j) // 2
    if find == nums[mid]:
        return mid 
    elif find < nums[mid]:
        return bi_search(nums, find, i, mid - 1)
    else:
        return bi_search(nums, find, mid + 1, j)