実行中の中央値を計算する必要があります:
入力: 、、vector 。
出力: vector 、ここではの中央値です。
(近似による不正行為はありません。正確な解を求めます。要素は大きな整数です。)
サイズ探索木を維持する簡単なアルゴリズムがあります。合計実行時間はです。(ここで「検索ツリー」とは、対数時間での挿入、削除、および中央値クエリをサポートする効率的なデータ構造を指します。)
しかし、これは私には少し愚かなようです。中央値だけでなく、サイズkのすべてのウィンドウ内のすべての順序統計を効果的に学習します。さらに、特にkが大きい場合、これは実際にはあまり魅力的ではありません(大きな検索ツリーが遅くなる傾向があり、メモリ消費のオーバーヘッドが自明ではなく、キャッシュ効率が悪いことが多いなど)。
大幅に改善できることはありますか?
下限はありますか(たとえば、単純なアルゴリズムは比較モデルに漸近的に最適ですか)。
編集:デビッドエップスタインは、比較モデルのための素敵な下限を与えました!それにもかかわらず、些細なアルゴリズムよりも少し賢いことをすることは可能だろうか?
たとえば、これらの線に沿って何かを行うことができます。入力ベクトルをサイズ部分に分割します。各部分をソートします(各要素の元の位置を追跡します)。そして、区分的にソートされたベクトルを使用して、補助データ構造なしで実行中の中央値を効率的に見つけますか?もちろん、これはまだO (n log kですが、実際には、配列のソートは検索ツリーを維持するよりもはるかに高速になる傾向があります。
編集2: Saeedは、検索ツリー操作よりもソートの方が速いと思う理由をいくつか見たいと思っていました。以下は、、n = 10 8の非常に簡単なベンチマークです。
- ≈8s:それぞれk個の要素を持つベクトルをソート
- ≈10s:要素を持つベクトルの並べ替え
- ≈80s:サイズkのハッシュテーブルでの挿入と削除
- ≈390s:サイズkのバランスの取れた検索ツリーでの挿入と削除
ハッシュテーブルは比較のためだけにあります。このアプリケーションでは直接使用しません。
要約すると、ソートとバランスの取れた検索ツリー操作のパフォーマンスにはほぼ50倍の差があります。そして、を増やすと事態はさらに悪化します。
(技術的詳細:データ=ランダムな32ビット整数。コンピューター=典型的な最新のラップトップ。テストコードはC ++で記述され、標準ライブラリルーチン(std :: sort)とデータ構造(std :: multiset、std ::を使用) unsorted_multiset)。2つの異なるC ++コンパイラ(GCCおよびClang)、および標準ライブラリの2つの異なる実装(libstdc ++およびlibc ++)を使用しました。伝統的に、std :: multisetは高度に最適化された赤黒木として実装されています。)