ある時点で、N
数値のコレクションがあり、中央値の要素がわかっているとしますM
。これで、新しい値 が与えられたX
ので、 を更新する必要があるかもしれませんM
。(むしろ、扱っている数値がすべて一意であると仮定する必要があります。また、すべてのサンプルは連続して受信されるため、同時実行性の問題はありません。)
新しい平均の計算は簡単です。古い平均を取り、 を足しX
、 を掛けN
、 で割りN + 1
ます。(これは、N 個の要素の平均がどのように定義されているかを調べれば明らかです。今のところ、数値についてはあまり心配していません。)
私の質問は次のとおりです。中央値を更新するという問題に、創造的/斬新な(またはおそらく最適な)アプローチを提案できる人はいますか? 以下に例 (私自身の設計の簡単なアイデア) を示し、少し分析します。
このサンプルではstd::forward_list
、C++ 11 が最近これに遭遇した場所であるため、を使用します。std::forward_list<T> sorted;
一般性を失うことなく、これを正しい方法で行っていると仮定します: これまでに 遭遇した要素 (タイプ T) の順序付けられたリストを維持しますT x;
。
sorted.merge(std::forward_list<T> {{ x }});
ところで、誰かがこれのためのより良い(より効率的/エレガントな)方法を持っているかどうか興味があります. 不満は大歓迎です。
X
は の一部になりました。私sorted
の考えを簡単に説明すると、次のようになります。
auto it = sorted.begin(), itend = sorted.end();
typename std::forward_list<T>::size_type count = std::distance(it, itend);
for (const auto &e : sorted) {
if (it == itend || ++it == itend) {
M = (count % 2) ? e : (e + M) / 2;
break;
} else { ++it; }
}
ここで起こる良いこと (多少見づらくない場合) は、次のとおりです。イテレータを 2 回前方に移動するため (そして安全に、2 回の比較の代償を払って追加することもできます)、 にend()
到達すると、適切な(中央値)値になります。奇数の要素M
がある場合は、そのサンプルだけです。そうでない場合は、この要素と古い (押し出された) 中央値の平均です。奇数と偶数が入れ替わるため、古いものと新しいもののどちらかM
が実際にコレクションに含まれます。この推論は正しいですよね?
私の O(3n) メソッドがゴミだと思うなら、コメントする必要はありません。出発点として提案しているだけです。