探索 > 二分探索

二分探索(にぶんたんさく、: binary searchBS)やバイナリサーチとは、ソート済み配列に対する探索アルゴリズムの一つ。

概要

編集





n [1]O

n1n/2(n-1)/2n/2(n/2)-1

具体例を示す。

データが見つかる例

編集

下記のようなソート済み配列から25を探しだすことを考える。なお、配列内に値の重複はない(あるデータと同じ値のデータは他に存在しない)ものとする。

位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28

?調N調n
位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28
結果 ? ? ? ? ? ? ? ? ? ?

1 + (10 - 1) / 2 = 5



 (1 + 10) / 2  1 + (10 - 1) / 2   + ( - ) / 2 #

512N14調n610
位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28
結果 n n n n N ? ? ? ? ?

位置6~10の中央の位置は、6 + (10 - 6) / 2 = 8

位置8のデータは22なので「N」、位置6~7までは「n」とわかる。目的のデータは位置9~10にあるかもしれない。

位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28
結果 n n n n N n n N ? ?

位置9~10の中央の位置は、9 + (10 - 9) / 2 = 9

位置9のデータは25なので目的のデータが見つかったことになる。位置10は調べていないが、配列内に値の重複はないという想定なので「n」としてよい。

位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28
結果 n n n n N n n N n

データが見つからない例(1)

編集

下記のようなソート済み配列から4を探しだすことを考える。なお、配列内に値の重複はないものとする。

位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28

1 + (10 - 1) / 2 = 5 



512N610調n14
位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28
結果 ? ? ? ? N n n n n n

位置1~4の中央の位置は、1 + (4 - 1) / 2 = 2

位置2のデータは3なので「N」、位置1も「n」とわかる。目的のデータは位置3~4にあるかも知れない。

位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28
結果 n N ? ? N n n n n n

343 + (4 - 3) / 2 = 3

35N43534調3n
位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28
結果 n N N n N n n n n n

データが見つからない例(2)

編集

下記のようなソート済み配列から29を探しだすことを考える。なお、配列内に値の重複はないものとする。

位置 1 2 3 4 5 6 7 8 9 10
データ 1 3 5 11 12 13 17 22 25 28

データの全体の一番右側が29より小さいので、データが見つからないという結果になる。

コード例

編集
int binary_search(int ary[], int key, int imin, int imax) {
    if (imax < imin) {
        return KEY_NOT_FOUND;
    } else {
        int imid = imin + (imax - imin) / 2;
        if (ary[imid] > key) {
            return binary_search(ary, key, imin, imid - 1);
        } else if (ary[imid] < key) {
            return binary_search(ary, key, imid + 1, imax);
        } else {
            return imid;
        }
    }
}
let find value (xa: 'T[]) =
  let rec ifind min max =
    if max < min then None
    else
      let c = min + (max - min) / 2
      if xa.[c] > value then ifind min (c - 1)
      else if xa.[c] < value then ifind (c + 1) max
      else Some c
  ifind 0 (xa.Length - 1)

find 8 [|1; 2; 4; 5; 6; 8; 11; 13|]
(define (find val xa)
  (letrec ((ifind
            (lambda (min max)
              (if (< max min)
                  #f
                  (let ((c (+ min (quotient (- max min) 2))))
                    (cond ((> (list-ref xa c) val) (ifind min (- c 1)))
                          ((< (list-ref xa c) val) (ifind (+ c 1) max))
                          (else c)))))))
    (ifind 0 (- (length xa) 1))))

実装上の間違い

編集

 "Although the basic idea of binary search is comparatively straightforward, the details can be surprisingly tricky ..."[2]Richard E. Pattis 1988調2015[3]

C imin + (imax - imin) / 2  (imax + imin) / 2 (imax + imin) / 2 imax + imin  int  (INT_MAX) imax + imin  INT_MAX Java  Arrays.binarySearch()  JDK 1.2 (1998) Java 6 (2006) [4]Coders at Work567

関連項目

編集

参照

編集
  1. ^ O記法では定数倍を無視できるので、単に とも書ける。
  2. ^ Knuth, Donald (1997). “Section 6.2.1: Searching an Ordered Table”. Sorting and Searching. The Art of Computer Programming. 3 (3rd ed.). Addison-Wesley. pp. 409–426. ISBN 0-201-89685-0 
  3. ^ Pattis, Richard E. (1988). “Textbook errors in binary searching”. SIGCSE Bulletin 20: 190–194. doi:10.1145/52965.53012.  cited at Kruse, Robert (1998). Data Structures and Program Design in C++. Prentice Hall. p. 280. ISBN 0-13-768995-0 
  4. ^ Bug ID: JDK-5045582 (coll) binarySearch() fails for size larger than 1<<30