web-dev-qa-db-ja.com

pythonのバイナリ検索アルゴリズム

pythonでバイナリ検索を実装しようとしていますが、次のように記述しました。ただし、needle_elementが配列内の最大要素より大きい場合は停止できません。

手伝ってくれますか?ありがとう。

def binary_search(array, needle_element):
    mid = (len(array)) / 2
    if not len(array):
        raise "Error"
    if needle_element == array[mid]:
        return mid
    Elif needle_element > array[mid]:
        return mid + binary_search(array[mid:],needle_element)
    Elif needle_element < array[mid]:
        return binary_search(array[:mid],needle_element)
    else:
        raise "Error"
13

needle_element > array[mid]、あなたは現在array[mid:]再帰呼び出しに。ただし、array[mid]は小さすぎるため、array[mid+1:]代わりに(それに応じて返されるインデックスを調整します)。

針が配列内のすべての要素よりも大きい場合、この方法でやると最終的に空の配列が得られ、期待どおりにエラーが発生します。

注:毎回サブアレイを作成すると、大きなアレイのパフォーマンスが低下します。代わりに、配列の境界を渡すことをお勧めします。

8
interjay

Lasse V. Karlsenが質問へのコメントで示唆しているように、lowerおよびupperインデックスを使用する方がはるかに良いでしょう。

これはコードになります:

def binary_search(array, target):
    lower = 0
    upper = len(array)
    while lower < upper:   # use < instead of <=
        x = lower + (upper - lower) // 2
        val = array[x]
        if target == val:
            return x
        Elif target > val:
            if lower == x:   # these two are the actual lines
                break        # you're looking for
            lower = x
        Elif target < val:
            upper = x
  • lower < upper(左側から)小さい数に達すると停止します
  • if lower == x: breakは、(右側から)より高い数値に達すると停止します

例:

>>> binary_search([1,5,8,10], 5)   # return 1
1
>>> binary_search([1,5,8,10], 0)   # return None
>>> binary_search([1,5,8,10], 15)  # return None
17
Rik Poggi

なぜbisectモジュールを使用しないのですか?それはあなたが必要とする仕事をするべきです---あなたが維持し、テストするためのより少ないコード。

8
Pierce

array [mid:]は、slow = slowと呼ばれるたびに新しいサブコピーを作成します。また、再帰を使用します。Pythonも遅いです。

これを試して:

def binarysearch(sequence, value):
    lo, hi = 0, len(sequence) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if sequence[mid] < value:
            lo = mid + 1
        Elif value < sequence[mid]:
            hi = mid - 1
        else:
            return mid
    return None
7
Ecir Hana

他の人が提案したようにアルゴリズムを改善できますが、まずそれがなぜ機能しないのか見てみましょう:

_needle_element > array[mid]_の場合、次に検索する二分された配列に要素midが含まれているため、ループに陥ります。したがって、針が配列にない場合、最終的に長さ1の配列を永久に検索することになります。代わりに_array[mid+1:]_を渡し(_mid+1_が有効なインデックスでない場合でも有効です)、最終的に長さゼロの配列で関数を呼び出します。したがって、len(array) == 0は、エラーではなく「見つかりません」という意味です。適切に処理してください。

2
alexis
def binary_search(array, target):
    low = 0
    mid = len(array) / 2
    upper = len(array)

    if len(array) == 1:
        if array[0] == target:
            print target
            return array[0]
        else:
            return False
    if target == array[mid]:
        print array[mid]
        return mid
    else:
        if mid > low:
            arrayl = array[0:mid]
            binary_search(arrayl, target)

        if upper > mid:
            arrayu = array[mid:len(array)]
            binary_search(arrayu, target)

if __name__ == "__main__":
    a = [3,2,9,8,4,1,9,6,5,9,7]
    binary_search(a,9)
1
user1342336

これは末尾再帰ソリューションです。これは、部分配列をコピーしてから、返されるインデックスを追跡するよりもきれいだと思います。

def binarySearch(elem, arr):
    # return the index at which elem lies, or return false
    # if elem is not found
    # pre: array must be sorted
    return binarySearchHelper(elem, arr, 0, len(arr) - 1)

def binarySearchHelper(elem, arr, start, end):
    if start > end:
        return False
    mid = (start + end)//2
    if arr[mid] == elem:
        return mid
    Elif arr[mid] > elem:
        # recurse to the left of mid
        return binarySearchHelper(elem, arr, start, mid - 1)
    else:
        # recurse to the right of mid
        return binarySearchHelper(elem, arr, mid + 1, end)
1
Sean

上記の答えはすべて真実ですが、コードを共有すると役立つと思います

def binary_search(number):
numbers_list = range(20, 100)
i = 0
j = len(numbers_list)
while i < j:
    middle = int((i + j) / 2)
    if number > numbers_list[middle]:
        i = middle + 1
    else:
        j = middle
return 'the index is '+str(i)
0
Maysara Alhindi

再帰を使用する:

def binarySearch(arr,item):
    c = len(arr)//2
    if item > arr[c]:
       ans = binarySearch(arr[c+1:],item)
       if ans:
          return binarySearch(arr[c+1],item)+c+1
    Elif item < arr[c]:
       return binarySearch(arr[:c],item)
    else:
       return c

binarySearch([1,5,8,10,20,50,60],10)
0
Mary

下位/上位インデックスがなければ、これも行う必要があります。

def exists_element(element, array):
    if not array:
        yield False

    mid = len(array) // 2
    if element == array[mid]:
        yield True
    Elif element < array[mid]:
        yield from exists_element(element, array[:mid])
    else:
        yield from exists_element(element, array[mid + 1:])
0
nettrino

再帰を使用して配列のキーのインデックスを返します。

round()は、floatを整数に変換し、コードを高速化する関数であり、期待されるcase [O(logn)]に進みます。

A=[1,2,3,4,5,6,7,8,9,10]
low = 0
hi = len(A)
v=3
def BS(A,low,hi,v):
    mid = round((hi+low)/2.0)
    if v == mid:
        print ("You have found dude!" + " " + "Index of v is ", A.index(v))
    Elif v < mid:
        print ("Item is smaller than mid")
        hi = mid-1
        BS(A,low,hi,v)
    else :
        print ("Item is greater than mid")
        low = mid + 1
        BS(A,low,hi,v)
BS(A,low,hi,v)
0
Anıl Selvi

バイナリ検索を実行している場合、配列がソートされていると推測しています。それが当てはまる場合、配列の最後の要素をneedle_elementと比較できるはずです。タコが言うように、これは検索が始まる前に行うことができます。

0
macduff

needle_elementは、開始する前に配列の境界内にあります。これにより、最後まで到達するためにいくつかの手順を実行する必要がないため、より効率的になります。

if needle_element < array[0] or needle_element > array[-1]:
    # do something, raise error perhaps?
0
Donald Miner

値がリストにある場合、ブール値を返します。

リストの最初と最後のインデックスをキャプチャし、中間値をキャプチャしてリストをループおよび分割します。各ループで同じことを行い、値の入力が中間値に等しいかどうかを比較します。

def binarySearch(array, value):
  array = sorted(array)
  first = 0
  last = len(array) - 1

  while first <= last:
    midIndex = (first + last) // 2
    midValue = array[midIndex]

    if value == midValue:
      return True
    if value < midValue:
      last = midIndex - 1
    if value > midValue:
      first = midIndex + 1
  return False
0
Israel Manzo