使用二进制搜索返回目标索引

时间:2017-02-13 13:16:57

标签: python algorithm binary-search

我必须返回数组目标元素的索引。

目前,当我搜索位于中点的元素时,它会返回正确的索引,但对于任何其他元素,它都不适合我。

我认为当我溢出数组时我犯了一个错误

aList = [1,3,5,6,8,9,10,12,34,56,78,456]
def recursiveBinarySearch(aList, target):
    #aList = sorted(aList)

    if len(aList) == 0:
        return False
    else:
        midpoint = len(aList) // 2
        if aList[midpoint] == target:
            return aList.index(target)
        else:
            if target < aList[midpoint]:
                return recursiveBinarySearch(aList[:midpoint],target)
            else:
                return recursiveBinarySearch(aList[midpoint+1:],target)

print(recursiveBinarySearch(aList,9))

8 个答案:

答案 0 :(得分:4)

这是因为每次进行递归调用时,都会传递不同的修改列表,并且索引将在每次调用时更改。例如,如果在数组的后半部分中搜索数字,则最终返回的值将小于len(aList)/2,因为只有这部分数组将在下一次迭代中传递。

解决方法是传递列表中的startend点,而不是拆分列表。

aList = [1,3,5,6,8,9,10,12,34,56,78,456]
def recursiveBinarySearch(aList, target, start, end):
    #aList = sorted(aList)

    if end-start+1 <= 0:
        return False
    else:
        midpoint = start + (end - start) // 2
        if aList[midpoint] == target:
            return midpoint
        else:
            if target < aList[midpoint]:
                return recursiveBinarySearch(aList, target, start, midpoint-1)
            else:
                return recursiveBinarySearch(aList ,target, midpoint+1, end)

print(recursiveBinarySearch(aList,455, 0, len(aList)))

答案 1 :(得分:3)

您的algortihm会在最后一个拆分列表中给出索引。 因此,如果您打印9的列表,您的答案是:

[1, 3, 5, 6, 8, 9, 10, 12, 34, 56, 78, 456]
[1, 3, 5, 6, 8, 9]
[8, 9]

返回索引1.这对于最后一个列表[8, 9]是正确的。 通过记住列表的长度可以很容易地解决这个问题。

aList = [1,3,5,6,8,9,10,12,34,56,78,456]
def recursiveBinarySearch(aList, target, index):
    #aList = sorted(aList)

    if len(aList) == 0:
        return False
    else:
        midpoint = len(aList) // 2

        if aList[midpoint] == target:
            return aList.index(target)+index
        else:
            if target < aList[midpoint]:
                return recursiveBinarySearch(aList[:midpoint],target, index)
            else:
                return recursiveBinarySearch(aList[midpoint:],target, index+len(aList[:midpoint]))


print(recursiveBinarySearch(aList,56,0))

这比以前的解决方案使用的内存少一点。当然,这也是更快的,尽管这是微不足道的。

答案 2 :(得分:1)

尝试编辑已接受的答案,因为它在搜索高于列表中的数字时失败但由于某种原因OP不接受编辑,这意味着答案仍然是错误。既然如此,我会在这里发布答案。当被要求查找大于1的值时,此答案不仅会修复IndexError,而且还会将args更改为kwargs,因此我们不必在每次调用时都将其传递给它们功能

aList = [-1,1,3,5,6,8,9,10,12,34,56,78,456] 

def binary_search(arr,item,low = 0, high = None):
    if high == None:
        high = len(arr)
    mid = low + (high-low) //2  
    if high - low + 1 <= 0 or mid==high:
        return False
    else:
        guess = arr[mid]
        if guess == item:
            return mid
        if item < guess:
            return binary_search(arr, item, low, mid)
        else:
            return binary_search(arr, item, (mid+1), high)

(binary_search(aList,457))

答案 3 :(得分:0)

我只是想分享我对这个问题的解决方案,看来有点简单:

def binary_search(array, value):
    index = int(len(array)/2) -1
    end = int(len(array)) - 1
    while array[index] != value:
        if index == end:
            return None
        elif array[index] > value:
            end = index
            index = int(index/2)
        elif array[index] < value:
            index = int((index+1 + end)/2)
    return index

答案 4 :(得分:0)

具有详细说明的解决方案

二进制搜索减少了搜索列表中项目的迭代次数。 我们必须首先将第一个索引初始化为0,将最后一个索引初始化为列表的长度-1。 然后我们将中间元素选择为(first + last)// 2 现在,我们必须将中间元素的值与查询元素进行比较。

  1. 如果它等于中间元素,那么我们可以按原样返回其索引。
  2. 如果查询元素小于中间元素,则我们将最后一个元素更新为mid-1。 (这样我们就可以迭代列表的第一部分)
  3. 如果查询元素大于中间元素,则我们将第一个元素更新为mid + 1。 (因此我们必须迭代列表的第二部分)

下面的代码段将清晰地显示上述语句。

aList = [-1,1,3,5,6,8,9,10,12,34,56,78,456] 

def binarySearch(numbers,item):
    first = 0 # first index
    last= len(numbers)-1 #last index
    found = False
    while( first<=last and not found):
        mid = (first + last)//2
        if numbers[mid] == item:
            found = True
            return mid
        else:            
            if item < numbers[mid]:
                last = mid - 1
            else:
                first = mid + 1 

print(binarySearch(aList,456))

注意:

  1. 由于我们在二进制搜索的每一步中都放置了一部分搜索用例,而另一半执行了搜索操作,这导致了O(log 2 N)。
  2. 如果未对给定列表进行排序,那么我们只需要在列表的开头进行排序

答案 5 :(得分:0)

下面是我的解决方法。

查看此visualization。 (那里也有一个编码解决方案!)

def binary_search(input_array, value):

    low = 0
    high = len(input_array) - 1

    while low <= high:
        mid = (low + high) / 2
        if input_array[mid] == value:
            return mid
        elif input_array[mid] < value:
            low = mid + 1
        else:
            high = mid - 1

    return -1

'''

答案 6 :(得分:0)

@Gijs Den Hollander代码的简化版本。条件语句经过简化,使用midpoint代替了len(aList[:midpoint]),就像我在评论中指出的那样:

def binarySearch(array, target, index=0):
    midpoint = len(array) // 2
    if array[midpoint] == target:
        return index + midpoint
    elif len(array) < 2:
        return -1
    else:
        return binarySearch(array[:midpoint], target, index) if target < array[midpoint] else binarySearch(array[midpoint:], target, midpoint+index)

答案 7 :(得分:0)

可以完成另一种简单的方法

def find_index(input_list, target, sorted=False):
    print('Input list: {}'.format(input_list))

    if sorted:
        input_list.sort()
        print('Sorting Input list: {}'.format(input_list))

    try:
        index = input_list.index(target)
    except ValueError as e:
        print(e)
        index = None

    return index

对于二进制搜索方法,

def bsearch(il, x):
    """binary search for an input list (il)"""
    il.sort()
    print('Input list is: {}'.format(il))

    l = len(il)
    m = round(l/2)

    n = il[m]
    print("m is {} and n is {}".format(m, n))

    if n == x:
        msg = 'The number "{}" found in list index "{}"'.format(x, m)
        print(msg)
        return x
    elif x < n:
        nl = il[:m]
    elif x > n:
        nl = il[m+1:]
    elif m < 1:
        return None

    return bsearch(nl, x)