Big-Oを正しく読み解く:定数が次数よりも重要になる場合
写真:Stackademic

Big-Oを正しく読み解く:定数が次数よりも重要になる場合

O(n log n)が必ずしもO(n²)に勝るわけではありません。データ量が少ない場合、決定的な要因となるのは式ではなく、CPUのキャッシュです。

Big-Oは、データが無限大に近づく際の傾向を表しています。問題は、実際のデータが無限大に近い状態になることはめったにないということです。

Big-Oは何を無視しているのか

この表記では、定数および低次項を意図的に省略している。あるアルゴリズム 100n と、あるアルゴリズム n はどちらもO(n)ですが、前者はどのようなデータサイズにおいても100倍も遅いのです。

典型的な例:小さな配列のソート

挿入ソートはO(n²)、シャッフルソートはO(n log n)である。それにもかかわらず、標準ライブラリはすべて、配列の要素数が数十未満の場合、挿入ソートを採用している。その理由は:

  • 順序付き挿入・検索であるため、CPUキャッシュは予測が可能であり、ミス予測がほぼ発生しない
  • 追加のメモリ割り当ては不要
  • ループ構造は非常に単純で、分岐命令が少ない

n = 20 の場合、小さな定数が成長度を圧倒的に上回る。

記憶は計算よりも高価だ

1回の加算には1ナノ秒もかからない。キャッシュミスによりRAMからデータを読み出すには、約100ナノ秒かかる。つまり、1回のキャッシュミスは100回の演算に相当する。

そのため、連続した配列を走査する方が、連結リストを走査するよりも通常は高速です。どちらもO(n)ですが、配列はメモリ上で連続して配置されており、CPUは次の要素をあらかじめ読み込んでいます。一方、連結リストでは、各ノードが別々の場所に配置されています。

Big-Oの正しい使い方

  • これを使って、最初から悪い設計を排除する――100万個の要素に対してO(n²)となることは議論の余地がない
  • 同程度の2つの選択肢から選ぶためにこれを使ってはならない — 実際に測定すべきだ
  • 実際のデータ規模がどれほど大きいかを常に確認してください。その答えは、たいてい想像しているよりも小さいものです
Chia sẻ

Thảo luận