IT1-CODE-POCKET

二分探索シミュレーター

二分探索は、整列済みの配列の真ん中を調べ、候補を毎回半分に減らしていく探索です。 low・mid・high の動きと、候補がどう減るかを1ステップずつ止めて確認できます。

動きを1ステップずつ確認する

要素数(個)
場面
配列 Nums target 8
    • 調べる(M)
    • 候補
    • 除外
    • 発見

    L=low(下端)/M=mid(中央)/H=high(上端)

    low 0
    mid
    high 5
    pos -1
    比較 0
    STEP 1 / 1 読み込み中です。

    パソコンではキーボードでも操作できます: 次へ / 前へ / スペース 再生・一時停止

    数値を自分で入力する

    わざと並びを崩した配列も入力できます。その場合は注意が表示され、二分探索が失敗する様子を確認できます。

    実行ログを見る(ここまでの処理)

      ALGORITHM

      二分探索とは何をしているか

      二分探索(バイナリサーチ)は、小さい順に並んだ配列に対して、真ん中の要素と探したい値 target を比べ、 大小の関係から目的の値が存在しない側を丸ごと捨てる探索です。 辞書で単語を引くとき、真ん中あたりを開いて「もっと後ろだ」と判断して前half を見なくなるのと同じ考え方です。

      使う変数は3つです。範囲の下端 low範囲の上端 high、そしてその中央 mid。 シミュレーターではこの3つがマスの上に L・M・H として表示され、候補から外れたマスは薄い破線になります。 「次へ」を押すたびに、薄いマスが一気に増えていく様子が確認できます。

      1回の比較で候補が半分になる

      線形探索は1回の比較で候補が1個しか減りませんが、二分探索は半分減ります。 この差は要素数が増えるほど大きくなります。

      要素数 線形探索(最悪) 二分探索(最悪)
      8 個 8 回 4 回
      1,000 個 1,000 回 約 10 回
      100 万個 100 万回 約 20 回

      100万個の中から探すのにたった20回で済みます。これが二分探索の強さで、 「整列してから探す」という手順に意味がある理由です。

      mid の小数は切り捨てる

      mid = (low + high) ÷ 2 で計算しますが、添字は整数でなければ配列を指せません。 そのため小数点以下は切り捨てます。たとえば low = 0high = 5 なら (0 + 5) ÷ 2 = 2.5 なので mid = 2 です。 シミュレーターでは、割り切れないときに「÷ は小数を切り捨てます」と表示されるので、実際の値と合わせて確認してください。

      整列されていないと失敗する

      二分探索が成り立つのは、「中央より大きいなら、目的の値は右側にしかない」と言い切れるからです。 並びが崩れていると、この判断が成り立ちません。捨てた側に目的の値が残っていても、二度と調べられないため見つけられません。

      実際に試してください:場面で「未整列」を選ぶと、配列の中に target があるのに見つからない様子が確認できます。 これが「二分探索は整列済みの配列にしか使えない」という条件の意味です。選択肢問題でこの前提を問われたら、この場面を思い出してください。

      +1 と -1 を忘れると終わらない

      範囲を更新するときは low = mid + 1high = mid - 1 と書きます。 この +1 / -1 は、調べ終わった mid を範囲から必ず外すためにあります。 これを忘れて low = mid と書くと、範囲が狭まらないまま同じ mid を調べ続け、処理が終わらなくなります(無限ループ)。

      条件で「± 1 を忘れた書き方」を選ぶと、範囲が狭まらなくなる様子を確認できます。 シミュレーターは同じ状態を繰り返したところで打ち切り、何が起きたかを表示します。

      CODE

      3つの書き方で見る二分探索

      擬似言語(DNCL風)・Python・JavaScript で並べました。変数名と処理の順番はすべて揃えてあります。

      Nums = [2, 5, 8, 11, 14, 20]
      target = 14
      low = 0
      high = 要素数(Nums) - 1
      pos = -1
      
      low <= high の間繰り返す:
      |mid = (low + high) ÷ 2
      |もし Nums[mid] == target ならば:
      ||pos = mid
      ||繰り返しを抜ける
      |そうでなくもし Nums[mid] < target ならば:
      ||low = mid + 1
      |そうでなければ:
      ⎿⎿ high = mid - 1
      
      表示する(pos)
      切り捨ての書き方:擬似言語の ÷、Python の //、JavaScript の Math.floor() は、 いずれも小数を切り捨てて整数の添字にするための書き方です。 JavaScript の / は小数のまま残るため、Math.floor() が必要になります。

      COST

      比較回数と計算量

      要素数を n とすると、候補は n → n/2 → n/4 → … と減り、1個になるまでの回数は約 log2(n) 回です。 シミュレーターで「中央」と「左端」を切り替えると、同じ配列でも比較回数が変わることが確認できます。

      場合 どんなとき 比較回数 計算量
      最良 最初の mid が target だった 1 回 O(1)
      最悪 端にある、または存在しない 約 log2(n) + 1 回 O(log n)
      前提 整列していない配列 使えない

      要素数が2倍になっても、比較回数は1回だけ増えます。線形探索が2倍になるのとは大きな違いです。 ただし、整列されていない配列を先に並べ替える場合は、その整列自体に手間(交換法や選択法なら n² に比例)がかかります。 1回だけ探すなら線形探索、何度も探すなら整列してから二分探索、という使い分けが問われることがあります。

      EXAM POINT

      共通テスト「情報Ⅰ」での出題ポイント

      二分探索は、穴埋めとトレース(値の追跡)の両方でよく出ます。狙われやすいのは次の5点です。

      1. mid の式:mid = (low + high) ÷ 2 の空欄。切り捨てになることも合わせて確認されます。
      2. 範囲の更新:low = mid + 1high = mid - 1 のどちらを使うか。「大きければ低い側を捨てる」の向きを間違えないことが要点です。
      3. 繰り返しの条件:low <= high<= 部分。< にすると、候補が1個になった場面を調べ落とします。
      4. 前提条件:「このアルゴリズムを使うために配列が満たすべき条件は何か」という問い。答えは「小さい順(または大きい順)に整列していること」です。
      5. 比較回数:「最大で何回の比較が必要か」。要素数 8 なら 4 回、16 なら 5 回のように、半分にしていく回数を数えます。
      トレース問題のコツ:紙に low・high・mid の3列を作り、1回の繰り返しごとに1行書き足していきます。 シミュレーターの変数表示と実行ログは、この表を画面上で作っているのと同じです。 まず自分で表を書き、その後シミュレーターで答え合わせをしてください。

      MISTAKES

      よくある間違い

      間違い 何が起きるか 正しくは
      整列していない配列に使う 配列の中にある値でも見つからない 先に整列する(または線形探索を使う)
      low = mid、high = mid と書く 範囲が狭まらず、処理が終わらない mid + 1 / mid - 1 にして mid を範囲から外す
      繰り返し条件を low < high にする 候補が1個になった場面を調べずに終わる low <= high にする
      大小の判断を逆にする 目的の値がある側を捨ててしまう 中央より大きいなら後半、小さいなら前半に絞る
      mid の小数を切り上げる 添字がずれて、範囲外を参照することがある 切り捨てて整数の添字にする

      CHECK

      理解度チェック

      まず自分で考え、答えを開く前に上のシミュレーターで確かめてみてください。

      Q1. Nums = [2, 5, 8, 11, 14, 20] で target = 8 のとき、最初の mid はいくつですか。
      mid = 2。 low = 0、high = 5 なので (0 + 5) ÷ 2 = 2.5、小数を切り捨てて 2 です。 Nums[2] は 8 なので、この場面では1回目の比較で見つかります(シミュレーターの「6個」+「中央」の場面)。
      Q2. 同じ配列で target = 2(左端)のとき、比較回数は何回になりますか。
      3回。 mid = 2(値 8)→ 大きいので前半へ、high = 1。mid = 0(値 2)… という順に絞られます。 同じ配列でも、探す値の位置によって比較回数が変わります。「左端」「右端」を切り替えて確認してください。
      Q3. 要素数 16 の配列では、最大で何回の比較が必要ですか。
      5回。 16 → 8 → 4 → 2 → 1 と半分にしていくと4回で候補が1個になり、その1個を確かめる比較を含めて5回です。 log2(16) = 4 なので log2(n) + 1 と考えると計算できます。
      Q4. 並びが崩れた配列に二分探索を使うと、必ず「見つからない」になりますか。
      いいえ、たまたま見つかることもあります。 崩れた並びでも、最初に調べた mid が偶然 target なら見つかります。 問題は「見つかることが保証されない」点です。正しく動くときと動かないときがあるアルゴリズムは使えません。 だからこそ「整列済み」という前提が必要になります。

      次に確認したいアルゴリズム