在Python列表中进行二进制搜索

时间:2016-07-13 08:09:49

标签: python python-2.7

我正在尝试在python中的列表上执行二进制搜索。 List是使用命令行参数创建的。用户输入他想要在数组中查找的数字,并返回元素的索引。由于某种原因,程序只输出1和无。代码如下。 非常感谢任何帮助。

import sys

def search(list, target):
  min = 0
  max = len(list)-1
  avg = (min+max)/2
  while (min < max):
    if (list[avg] == target):
      return avg
    elif (list[avg] < target):
      return search(list[avg+1:], target)
    else:
      return search(list[:avg-1], target)

  print "The location of the number in the array is", avg

# The command line argument will create a list of strings                               
# This list cannot be used for numeric comparisions                                     
# This list has to be converted into a list of ints                                     
def main():

  number = input("Please enter a number you want to search in the array !")
  index = int(number)
  list = []
  for x in sys.argv[1:]:
    list.append(int(x))
  print "The list to search from", list

  print(search(list, index))

if __name__ == '__main__':
  main()

CL :
Anuvrats-MacBook-Air:Python anuvrattiku$ python binary_search.py 1 3 4 6 8 9 12 14 16 17 27 33 45 51 53 63 69 70
Please enter a number you want to search in the array !69
The list to search from [1, 3, 4, 6, 8, 9, 12, 14, 16, 17, 27, 33, 45, 51, 53, 63, 69, 70]
0
Anuvrats-MacBook-Air:Python anuvrattiku$ 

4 个答案:

答案 0 :(得分:3)

在Python2和Python3中,您可以使用评论中所写的bisect。 用以下

替换您的搜索
from bisect import bisect_left

def search(alist, item):
    'Locate the leftmost value exactly equal to item'
    i = bisect_left(alist, item)
    if i != len(alist) and alist[i] == item:
        return i
    raise ValueError

alist = [1,2,7,8,234,5,9,45,65,34,23,12]
x = 5
alist.sort() # bisect only works on sorted lists
print(search(a, x)) # prints 2 as 5 is on position 2 in the sorted list

此外,AS SortedCollection (Python recipe)可能很有用。

以下代码(from here)执行二进制搜索并返回位置,如果找到该项目的话。

def binarySearch(alist, item):
    first = 0
    last = len(alist)-1
    found = False

    while first<=last and not found:
        pos = 0
        midpoint = (first + last)//2
        if alist[midpoint] == item:
            pos = midpoint
            found = True
        else:
            if item < alist[midpoint]:
                last = midpoint-1
            else:
                first = midpoint+1
    return (pos, found)

如果在上面的例子中使用,将返回(2, True)

答案 1 :(得分:3)

嗯,你的代码中有一些小错误。要找到它们,您应该使用调试器,或者至少添加跟踪以了解发生的情况。这是您的原始代码,其中包含使问题不明显的痕迹:

def search(list, target):
  min = 0
  max = len(list)-1
  avg = (min+max)/2
  print list, target, avg
  ...

你可以立即看到:

  • avg
  • 下搜索跳过avg-1的子数组时
  • 当您在子数组中搜索时,您将获得该子数组中的索引

修复现在很简单:

elif (list[avg] < target):
      return avg + 1 + search(list[avg+1:], target)  # add the offset
    else:
      return search(list[:avg], target)  # sublist ends below the upper limit

这不是全部,当你用min == max结束循环时,你不返回任何东西(意味着你返回None)。最后但并非最不重要的是从不使用标准Python库中的名称作为您自己的变量。

所以这是固定代码:

def search(lst, target):
  min = 0
  max = len(lst)-1
  avg = (min+max)/2
  # uncomment next line for traces
  # print lst, target, avg  
  while (min < max):
    if (lst[avg] == target):
      return avg
    elif (lst[avg] < target):
      return avg + 1 + search(lst[avg+1:], target)
    else:
      return search(lst[:avg], target)

  # avg may be a partial offset so no need to print it here
  # print "The location of the number in the array is", avg 
  return avg

答案 2 :(得分:0)

您没有得到正确结果的原因是因为在每次递归调用中,您的代码都在发送切片数组。因此阵列长度不断减少。理想情况下,您应该找到一种方法来发送原始数组并仅使用开始,结束索引。

答案 3 :(得分:0)

@Serge Ballesta的解决方案无疑是该问题的正确答案。

我将添加解决该问题的另一种方法:

def search(arr, item, start, end):

  if end-start == 1:
    if arr[start] == item:
        return start
    else:
        return -1;

  halfWay = int( (end-start) / 2)

  if arr[start+halfWay] > item:
    return search(arr, item, start, end-halfWay)
  else:
    return search(arr, item, start+halfWay, end)

def binarysearch(arr, item):
  return search(arr, item, 0, len(arr))

arr = [1, 3, 4, 6, 8, 9, 12, 14, 16, 17, 27, 33, 45, 51, 53, 63, 69, 70]

print("Index of 69: " + str(binarysearch(arr, 69))) # Outputs: 16