計算量と二分探索
同じ問題を解くにも、アルゴリズムによって実行時間は大きく異なります。この効率を客観的に評価する指標が計算量です。計算量の考え方を理解し、高速な探索アルゴリズムである「二分探索」の仕組みを学びましょう。
1. アルゴリズムの効率の指標:計算量
アルゴリズムの効率を測るとき、「手元のPCで実行したら 0.5秒だった」という測定の仕方は不適切です。なぜなら、PCの性能(CPUやメモリの速度)やプログラミング言語の種類によって実行時間は変わってしまうからです。
そこで、コンピュータサイエンスでは「処理するデータ数Nが増えたとき、計算ステップ数がどの程度の割合で増加するか」という数学的な評価基準を使います。これが計算量(Computational Complexity)です。
計算量の表記には、O記法(Big-O Notation)を使います。
- O(1):定数時間
データ数Nに関わらず、常に一定の時間で完了します。例:配列のインデックスアクセス - O(log N):対数時間
データ数Nが増加しても計算時間の増加が少ない、効率のよいオーダーです。例:二分探索 - O(N):線形時間
Nの増加に比例して計算時間も増えます。例:線形探索 - O(N²):二乗時間
データが少し増えるだけで計算時間が急激に爆発します。Nが10倍になると時間は100倍に。例:単純なソート
2. 線形探索(Linear Search):O(N)
あるデータ群(例えば配列)の中から、目的の値を見つけ出す最も素朴な方法が線形探索(Linear Search)です。
これは、配列の「先頭の要素から末尾に向かって、順番に1つずつ目的の値と一致するかチェックする」という方法です。
最悪の場合、目的のデータが末尾にあるか存在しないため、N回の比較が必要です。よって最悪計算量は O(N) です。
3. 二分探索(Binary Search):O(log N)
検索対象のデータが事前にソート(並び替え)されている場合、高速な二分探索(Binary Search)を使えます。
二分探索の考え方は、辞書で単語を引くときや、数当てゲーム(1〜100の中で数字を当てるゲーム)と全く同じです。
- まず、並んでいるデータ群の「ちょうど真ん中の値」を確認します。
- 探したいターゲットの値が、その真ん中の値よりも「大きい」か「小さい」かを判定します。
- もしターゲットの方が大きければ、真ん中より「左側半分」には絶対にデータはないことが確定するため、探索範囲を「右側半分」に絞り込みます(小さければその逆)。
- 絞り込まれた新しい範囲に対して、再びステップ1(真ん中を確認)を繰り返します。
この手法は要素数が大きくなるほど効果的です。探索範囲が毎ステップで半分に縮小していくため、高速に処理できます。
データ数Nに対する最悪計算回数は、数学的に $\log_2 N$ 回になります。よって、最悪計算量は O(log N) です。
4. O(N) と O(log N) の速度差
データ数が少ないときは、線形探索 O(N) も二分探索 O(log N) も実行時間に大きな差はありません。 しかし、データ数が大きくなると、この2つの実行時間には大きな差が生じます。
例えば、日本の全人口(約1億2000万人)の名簿から特定の名前を検索する場合を考えてみます。
- 線形探索 O(N) の場合:
最悪で 1億2000万回 の比較ループを実行します。スマホやPCでも、データ読み込みとループ処理で数秒〜数十秒の待ち時間が発生します。 - 二分探索 O(log N) の場合:
最悪でもわずか 27回($\log_2 120,000,000 \approx 26.8$)の比較だけで完了します。27回といえば、CPUからすれば一瞬(数ナノ秒)であり、人間には完全にリアルタイム(0秒)で表示されます。
データ数が大幅に増えても計算回数は数十回しか増えません。この特徴により、大規模な検索エンジンなどのシステムにおいて高速な検索処理が可能になります。
次のセクションでは、直線的な並びではなく、データの親子関係などを網の目のように表現する非線形データ構造「木構造」と「グラフ」について学びます。
スマートフォンの連絡先やSNSのユーザー検索など、多くのユーザーデータの中から、目的の結果がすばやく表示されるのはなぜでしょうか。
- データベースインデックス: データベースの検索を高速化する「インデックス」と呼ばれる機能は、内部で二分探索を応用したデータ構造(B-Treeなど)を利用しています。あらかじめソートされた形でインデックスが作成されているため、数億件のデータがあっても、わずか数回のデータ比較で目的のレコードに到達できます。
- 計算量の差がサーバー代を決める: 1回の検索に、線形探索 $O(N)$ を使うとサーバーのCPUはフル稼働し、アクセスが集中するとシステムがダウンしてしまいます。しかし、二分探索 $O(\log N)$ を使用すれば、CPUにかかる負荷は数万分の一に抑えられます。これは、サービスの維持にかかる電気代やサーバーの維持費が何万分の一に激減することを意味します。
プログラムが正しく動作するだけでなく、計算量を意識した設計が、大規模なWebサービスを効率的に運用するためには必要です。
アルゴリズムの性能評価(O記法)における、代表的な計算量の増加傾向の強さと、二分探索の前提条件を整理しておきましょう。
- 計算量オーダーの大小関係(効率が良い順):
- $O(1) < O(\log N) < O(N) < O(N \log N) < O(N^2) < O(2^N)$
- データ数 $N$ が大きくなると、オーダー間の実行ステップ数は大きく異なります。
- 二分探索の前提条件:
- 検索対象のデータが事前にソート(並び替え)されている必要があります。ソートされていないランダムなデータに対しては二分探索を直接適用できず、線形探索を行う必要があります。