中央値を追跡する最良の方法は何ですか?


8

私は質問を読み、それを解決する方法についての入力を探しています。

数値はランダムに生成され、(拡張)配列に格納されます。中央値をどのように追跡しますか?

問題を解決できる2つのデータ構造があります。1つはバランスのとれたバイナリツリーで、もう1つは2つのヒープで、要素の最大の半分と最小の半分を追跡します。これら2つのソリューションの実行時間はと同じだと思いますO(n lg n)が、自分の判断はわかりません。

中央値を追跡する最良の方法は何ですか?

私の試み:

この質問では、中央値を追跡するにはヒープが最良の方法だと思います。大きなヒープと小さなヒープの2つのヒープがあり、これらは順次である必要はありません。まず、配列の要素の平均値を計算します。要素が平均値より小さい場合は、numを小さなヒープに入れます。逆に、numを大きなヒープに入れました。大きいヒープの数が小さいヒープの数と等しい場合、小さいヒープの最大のヒープと大きいヒープの最小のヒープが中央値になります。2つのヒープのサイズが異なる場合は、大きいサイズのヒープからルート要素をポップし、小さいサイズのヒープのルートにプッシュします。大きなヒープの場合、ルート要素は最小の要素であり、小さなヒープの場合、ルート要素は最大の要素です。このようにして、2つのヒープのサイズが同じであるか、デジタル差がある場合、

このソリューションの実行時間はO(m * n)であると思います。mは、アンバランスヒープを調整する時間を意味します。

これは中央値を追跡する最良の方法ですか?


中央値のみを追跡する必要がある場合、2つは基本的に同じ複雑さを持っていますが、ヒープベースのアプローチはより少ないメモリを使用し(その構造はポインターを必要とする代わりに暗黙的です)、一般的に同様に高速です(通常は連続して格納されるため、通常はキャッシュの使用率が向上します)。
ジェリーコフィン

2
stackoverflow.com/questions/2579912/…必要であれば、線形ソリューションになります。
JBキング

2
へへーstd::nth_element誰か?
ビリーONeal

5
これは実際には、SOに対する質問のように聞こえます。
マークB

平均値は、意味をなさないほどに非常に誤解を招く可能性があります。イメージングするだけでたくさんの小さな数字(たとえば1..999)と10 ^ 8ができます。これらの1000個の数値の平均値は〜10 ^ 5なので、10 ^ 8以外のすべてを小さなヒープに入れることになります。したがって、アルゴリズムには悪い最悪の場合の動作があります。
user281377

回答:


1

この問題を解決するデータ構造はおそらく2つ以上あります。1回のパスでメモリが制限されている近似中央値およびその他の分位数を見てください

2つのヒープは使用しません。アルゴリズムを変更して、定期的に中央値の概算値を定期的に取得できると思います。もちろん、近似がどの程度優れているかは、アルゴリズムを通過したデータ量など、多くの要因に依存します。


0

より良い解決策は、スキップリストを使用することです。挿入先のリストは常にソートされたリストとして維持されているため(作成方法の事実により)、挿入の複雑さはO(log n)です。最初の挿入では中央値がゼロのコストで提供されるという事実を利用します(挿入されたアイテムは中央値です)。追加の挿入が行われるたびに、リストは引き続きソートされ、中央値自体が単一のインデックスによって上下にドリフトします。この比較はO(1)です。

総複雑度= O(log n)


各要素の合計の複雑さは次のO(log n)とおりです。n個の要素を挿入すると複雑になりますO(n log n)
グレッグジャクソン

1
確かに、しかし「実行中の中央値」の場合、無制限の要素のセットを挿入していると主張することができますが、複雑度がO(無限大のログn)であると言っても意味がありません。;-)
マイケルヘイズ

ええと...ええ、私の答えはヒープよりも良いことはありません。フィボナッチヒープには、O(1)の挿入とO(lg n)の削除があります。私はそれを使用したことがありません。
マイケルヘイズ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.