【问题标题】:How do I return the index of the target element in a Python array?如何返回 Python 数组中目标元素的索引?
【发布时间】:2020-09-29 21:47:39
【问题描述】:

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

我认为我在拆分数组时犯了一个错误:

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

【问题讨论】:

  • 是否有可能当我找到元素时,由于二进制搜索将数组分成两半的性质,数组只是那个元素?

标签: python algorithm binary-search


【解决方案1】:

那是因为每次进行递归调用时,都会传递一个不同的修改列表,并且每次调用都会更改索引。例如,如果您在数组的后半部分搜索一个数字,则最终返回的值将小于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)))

【讨论】:

  • 当被要求查找一个大于列表中未包含的值时,您的答案将失败并返回 IndexError。我已经编辑了您的答案以解决问题,并将您的 args 编辑为 kwargs,因此我们不必在每次调用函数时都传递它们。
【解决方案2】:

您的算法给出了最后一个拆分列表中的索引。 因此,对于您的答案,如果您打印 9 的列表,我们将得到以下信息:

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

Wich 返回索引 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 + midpoint)
                

print(recursiveBinarySearch(aList,56,0))

与之前的解决方案相比,这使用的内存要少一些。当然这也更快,尽管那是微不足道的。

【讨论】:

    【解决方案3】:

    尝试编辑接受的答案,因为它在搜索高于列表中的数字时失败,但由于某种原因 OP 不接受编辑,这意味着答案仍然错误。既然如此,我将在这里发布答案。这个答案不仅修复了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))
    

    【讨论】:

      【解决方案4】:

      我只是想分享一下我对这个问题的解决方法,看起来简单一点:

      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
      

      【讨论】:

        【解决方案5】:

        详细解释的解决方案

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

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

        下面的代码sn -p 可以清晰的看到上面的语句。

        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(log2 N)。
        2. 如果给定的列表没有排序,那么我们只需要对列表的开头进行排序

        【讨论】:

          【解决方案6】:

          以下是我的解决方案。

          看看这个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
          

          '''

          【讨论】:

            【解决方案7】:

            @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)
            

            【讨论】:

              【解决方案8】:

              还有一个简单的方法,

              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)
              

              【讨论】:

                猜你喜欢
                • 2014-04-28
                • 1970-01-01
                • 1970-01-01
                • 2011-10-25
                • 2012-11-13
                • 1970-01-01
                • 1970-01-01
                • 2015-08-15
                • 1970-01-01
                相关资源
                最近更新 更多