1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Ruby]バイナリーサーチとは

Last updated at Posted at 2022-01-15

学習したことのアウトプットとして

バイナリーサーチを用いた問題、理屈はわかるが、実際自分でコードを描こうとすると脳が混乱…。
ので、自分なりに整理してみようかと。

##”バイナリーサーチ”とは
ソート済みのリストや配列に入ったデータ(同一の値はないものとする)に対する検索を行うときに用いられる手法。
中央の値を確認し、検索したい値との大小関係を用いて、検索したい値が中央の値の右にあるか、左にあるかを判断。
それを繰り返し、片側には存在しないことを確かめながら検索していく方法。

例)ある配列にある13の位置を知りたい

2 3 5 6 8 10 11 13 16
4番目の"8"が要素の中央。13は8より大きいので、次は"10"を左端として検索
10 11 13 16
6番目の"11"が要素の中央。13は11より大きので、次は"13"を左端として検索
13 16
7番目の"13"が要素の中央。検索したい13と合致
「13は配列の7番目」

という風な感じ。理屈自体は難しいものではないかと。

要素数が偶数の場合、「中央」は数が少ない方(左側)が優先されるのか?
詳しい人がいらっしゃればコメントいただけると幸いです。

###問題
以下の配列に任意の値が存在するかどうか、そして何番目に存在するのか、検索するコードを作成しましょう。
添字が0の要素、つまり以下の配列における「1」は「配列の0番目に存在する」と表現します。

array=[1,3,5,6,9,10,13,20,26,31]

任意の値が配列内に存在しない場合は、「値は配列内に存在しません」と表示し、
存在する場合は、配列の何番目にあるかを表示してください。
※配列の上限である32以上の値による検索は想定しないものとする。

###模範解答

def binary_search(array, right, target)
  left = 0
  while left <= right
    center = (left + right) / 2
    if array[center] == target
      return center
    elsif array[center] < target
      left = center + 1
    else
      right = center - 1
    end
  end
  return -1 
end

array=[1,3,5,6,9,10,13,20,26,31]

puts "検索したい数字を入力してください"
target = gets.to_i
number_of_elements = array.length

result = binary_search(array, number_of_elements, target)

if result == -1
  puts "#{target}は配列内に存在しません"
else
  puts "#{target}は配列の#{result}番目に存在します "
end

###解説

1〜14行目
def binary_search(array, right, target)
  left = 0
  while left <= right
    center = (left + right) / 2
    if array[center] == target
      return center
    elsif array[center] < target
      left = center + 1
    else
      right = center - 1
    end
  end
  return -1 
end
検索したい値との大小関係を用いて、検索したい値が中央の値の右にあるか、左にあるかを判断して、片側には存在しないことを確かめながら検索を行う処理を行ってる。

たとえば、targetとして"20"を入力した場合を考えてみる

1回目のループ

def binary_search(array, right, target) #(配列,10(配列の数),20)
  left = 0
  while left <= right #0 <= 10 はtureで処理が実行される
    center = (left + right) / 2 #要素の中央  (0+10) / 2 = 5
    if array[center] == target #array[5]は"10"でfalseなので、この処理はされない
      return center
    elsif array[center] < target #trueなのでこの処理が実行される
      left = center + 1 #2回目のループではleft=6(配列の中央から右側に検索範囲を絞る)
    else
      right = center - 1
    end
  end
  return -1 
end

2回目のループ

def binary_search(array, right, target) #(配列,10(配列の数),20)
  left = 6 #1回目のループより
  while left <= right #6 <= 10 はtureで処理が実行される
    center = (left + right) / 2 #要素の中央  (6+10) / 2 = 8
    if array[center] == target #array[8]は"26"でfalseなので、この処理はされない
      return center
    elsif array[center] < target #26 < 20 でfalse
      left = center + 1
    else
      right = center - 1 #ここの処理がされる。3回目のループではright=9(1回目で絞った配列からさらに中央から左側に検索範囲を絞る)
    end
  end
  return -1 
end

3回目のループ

def binary_search(array, right, target) #(配列,10(配列の数),20)
  left = 6 #1回目のループより
  while left <= right #6 <= 9(2回目のループより) はtureで処理が実行される
    center = (left + right) / 2 #要素の中央  (6+9) / 2 = 7
    if array[center] == target #array[7]は"20"でture
      return center   #7 が返り値となる
    elsif array[center] < target 
      left = center + 1
    else
      right = center - 1 
    end
  end
  return -1 
end

13行目のreturn -1は何も当てはまるときがないときに、最終的な返り値になる。

返り値を元に条件分岐を利用して出力内容を設定する。

記事を書いて、少し自分の中でも整理できたのでよかった!

1
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?