なぜヒストグラムを作成しないのですか?私。いくつかのカテゴリのそれぞれに該当するケース(値)の数。カテゴリは、変数の連続したオーバーラップしない間隔である必要があります。
このヒストグラムを使用すると、中央値の最初の推定値([中央値は[a、b]の間にあります)と、この間隔(H)に入る値の数を知ることができます。 H < = Nの場合は、この間隔以外でこれらを無視して数字をもう一度読み、その間隔内の数字をRAMに移動します。中央値を求める。
H> Nの場合、間隔の新しいパーティションを作成し、手順を繰り返します。 2回または3回以上の繰り返しは必要ありません。
各パーティションに対して、a、b、デルタ、および各サブインターバルに入る値の数を格納するだけでよいことに注意してください。
EDIT。それは私が期待していたもう少し複雑なものになっていった。中央値が入る間隔を見積もった後の各反復で、この間隔の右側と左側に「いくら」のヒストグラムを残すかを考慮する必要があります。私は停止条件も変えました。とにかく、私はC++の実装を行った。
#include <iostream>
#include <algorithm>
#include <time.h>
#include <stdlib.h>
//This is N^2... or just the number of values in your array,
//note that we never modify it except at the end (just for sorting
//and testing purposes).
#define N2 1000000
//Number of elements in the histogram. Must be >2
#define HISTN 1000
double findmedian (double *values, double min, double max);
int getindex (int *hist);
void put (int *hist, double min, double max, double val, double delta);
int main()
{
//Set max and min to the max/min values your array variables can hold,
//calculate it, or maybe we know that they are bounded
double max=1000.0;
double min=0.0;
double delta;
double values[N2];
int hist[HISTN];
int ind;
double median;
int iter=0;
//Initialize with random values
srand ((unsigned) (time(0)));
for (int i=0; i<N2; ++i)
values[i]=((double)rand()/(double)RAND_MAX);
double imin=min;
double imax=max;
clock_t begin=clock();
while (1) {
iter++;
for (int i=0; i<HISTN; ++i)
hist[i]=0;
delta=(imax-imin)/HISTN;
for (int j=0; j<N2; ++j)
put (hist, imin, imax, values[j], delta);
ind=getindex (hist);
imax=imin;
imin=imin+delta*ind;
imax=imax+delta*(ind+1);
if (hist[ind]==1 || imax-imin<=DBL_MIN) {
median=findmedian (values, imin, imax);
break;
}
}
clock_t end=clock();
std::cout << "Median with our algorithm: " << median << " - " << iter << "iterations of the algorithm" << std::endl;
double time=(double)(end-begin)/CLOCKS_PER_SEC;
std::cout << "Time: " << time << std::endl;
//Let's compare our result with the median calculated after sorting the
//array
//Should be values[(int)N2/2] if N2 is odd
begin=clock();
std::sort (values, values+N2);
std::cout << "Median after sorting: " << values[(int)N2/2-1] << std::endl;
end=clock();
time=(double)(end-begin)/CLOCKS_PER_SEC;
std::cout << "Time: " << time << std::endl;
return 0;
}
double findmedian (double *values, double min, double max) {
for (int i=0; i<N2; ++i)
if (values[i]>=min && values[i]<=max)
return values[i];
return 0;
}
int getindex (int *hist)
{
static int pd=0;
int left=0;
int right=0;
int i;
for (int k=0; k<HISTN; k++)
right+=hist[k];
for (i=0; i<HISTN; i++) {
right-=hist[i];
if (i>0)
left+=hist[i-1];
if (hist[i]>0) {
if (pd+right-left<=hist[i]) {
pd=pd+right-left;
break;
}
}
}
return i;
}
void put (int *hist, double min, double max, double val, double delta)
{
int pos;
if (val<min || val>max)
return;
pos=(val-min)/delta;
hist[pos]++;
return;
}
また、アルゴリズムの結果と比較するためのメジアン(ソート)の単純な計算も含まれています。4回または5回の反復で十分です。つまり、ネットワークまたはHDDからセットを4〜5回読み取るだけです。
一部の結果:あなたは、アルゴリズムを並列化したい場合は
N2=10000
HISTN=100
Median with our algorithm: 0.497143 - 4 iterations of the algorithm
Time: 0.000787
Median after sorting: 0.497143
Time: 0.001626
(Algorithm is 2 times faster)
N2=1000000
HISTN=1000
Median with our algorithm: 0.500665 - 4 iterations of the algorithm
Time: 0.028874
Median after sorting: 0.500665
Time: 0.097498
(Algorithm is ~3 times faster)
は、各マシンは、N個の要素を持っているし、ヒストグラムを計算することができます。それが計算されると、それらはマスターマシンに送信され、すべてのヒストグラムが集計されます(簡単ですが、実際は小さくなります...アルゴリズムは2間隔のヒストグラムでも機能します)。次に、新しいヒストグラムを計算するためにスレーブマシンに新しい命令(すなわち、新しい間隔)を送る。各マシンは、他のマシンが所有するN個の要素についての知識は必要ないことに注意してください。
2つのヒープを使用して実行できます。この最も一般的な答えを見る[質問] [http://stackoverflow.com/questions/3440905/find-the-median-from-a-stream-of-integers/3441042#3441042] – deinst
@ deinst-そのアプローチの必要性あなたがすべてをメインメモリに収めたいのであれば、いくつかの重要な変更はありません。 – templatetypedef
中央値を求めるための線形時間アルゴリズムがあります。あなたは分散コンピューティングについて述べましたあなたは、N個のメモリ要素を持つK個のプロセッサをそれぞれ持っていて、良い分散実行時間を得たいと仮定していますか?どこでKで割りますか?そのためには理想的にはO(N log N)アルゴリズムではなく、線形時間の基本アルゴリズムが必要です。 – user2566092