2012-05-03 10 views
1

各要素が別の要素を指している大きな配列の要素のサブセットをループする必要があります(大きなグラフの接続されたコンポーネントの検出に起因する問題)。配列対マップの性能

私のalgoは次のようになります: 1.第1要素を考慮してください。 2.次の要素を前の要素が指しているものとみなしてください。 3.新しい要素が発見されなくなるまでループします。 4. 1-3で考慮していない次の要素を検討し、1に戻ります。 考慮する要素の数は要素の総数よりもはるかに少ないことに注意してください。

私が今見るもののために、私はいずれかを実行できます。

//create a map of all element, init all values to 0, set to 1 when consider 
map<int,int> is_set; // is_set.size() will be equal to N 

または

//create a (too) large array (total size), init to 0 the elements to consider 
int* is_set = (int*)malloc(total_size * sizeof(int)); // is_set length will be total_size>>N 

を、私はそれが配列の場合のみ一定のですが(Nを記録)マップ内のキーへのアクセスがOであることを知っているが、 mallocがより多くのメモリを必要とする一方で、作成コストがそれほど高くないかどうかはわかりません。

+1

それほど解決策ではありませんが、mallocを使用する代わりに 'int * is_set = new int [total_size];'を実行できますか? – josephthomas

+0

@josephthomasはそれが単なるブロックメモリの割り当てなので何でも変わるのですか? – Arno

+1

あなたの場合、いいえ、あなたの質問はC++とタグ付けされています。それはもっと 'C++スタイル 'です。 mallocとnewの間には違いがあります。 – josephthomas

答えて

7

疑問がある場合は、は両方の代替品のパフォーマンスを測定しますこれは、どのアプローチがアプリケーションにとって最速になるかを知る唯一の方法です。

つまり、ワンタイムの大きなmallocは一般的にひどく高価ではありません。また、マップはO(log N)ですが、big-Oは少なくとも私の経験ではstd::mapの実装では比較的大きな定数を隠しています。アレイのアプローチがこの場合より速いことに気づくことはありませんが、確かに知る唯一の方法は測定することです。

マップには大量の初期メモリ割り当てはありませんが、オブジェクトの存続期間に渡って小さな割り当てが多数あります(新しい要素を挿入するたびに別の割り当てが行われるたびに要素を削除すると、別の要素が解放されます)。これらの数が非常に多い場合は、ヒープが断片化する可能性があり、アプリケーションが同時に何をしているのかによってパフォーマンスに悪影響を与える可能性があります。

+0

マップの割り当ては、要素が順序であり、マップの終わりから償却された一定時間で初期化できるので問題ではありません。私に迷惑をかけている鍵にアクセスするのは複雑です。 – Arno

+1

@Arno:配列要素へのアクセスはO(1)です。マップ要素にアクセスするためのO(log n)時間よりも大幅に優れています。繰り返しますが、あなたの最善の策は、測定することです。 –

1

マップのアクセスキーはO(log N)ですが、配列に対しては定数ですが、mallocの作成にはコストがかかりませんが、さらにメモリが必要ですか?

ダイナミックアロケーションが問題である場合、マップ内の各エントリはマップ内でより大きな問題になります。データ構造体としては、int型の単純な配列ではなくビットマップを使用できます。これにより、32ビットのアーキテクチャでは32の倍数で配列のサイズが縮小されます。配列にインデックスをマッピングするための余分なコストは、ほとんどの場合、余分なメモリのコストよりもはるかに小さくなります。コンパクトで、より少ないキャッシュラインに収まることができます。

他の点として、セット内の要素の密度が小さいかどうかを検討する必要があります。エントリが非常に少ない場合(グラフが疎な場合)、どちらのオプションも問題ありません。最後のオプションとして、pair<int,int>のベクトルを使用してマップを手動で実装し、それらを短くしてバイナリ検索を使用することができます。これは割り当ての数を減らし、ソートにいくらかの追加コストがかかり、マップよりもよりコンパクトなO(log N)ソリューションを提供します。それでも、私はビットマスクのために行くことを試みるでしょう。

+0

私はビットマップのこのアプローチに精通していません。私はそれについての情報やアドバイスを探して、興味深い考えのように聞こえます。 Thx – Arno

+0

@Arno:ビットマップを実装するタイプ( 'std :: bitset'(固定サイズ)と悪名高い' std :: vector 'を含む)がありますが、基本的には各値を内部表現のちょうど1ビットにマッピングします。要素Nを設定するには、位置(N/32)の符号なし整数を更新し、(N%32)ビットを設定します。これは、データのコンパクトな表現を提供する。 –

2

索引による検索が(通常のCスタイルの配列のように)ニーズに合っている場合、おそらくstd::mapは適切なクラスではありません。代わりに、動的ランタイム割り当てが必要な場合はstd::vector、コレクションが固定サイズでCスタイルのポインタの代わりに最速の境界安全なものが必要な場合はstd::arrayを使用することを検討してください。

この詳細については、previous postをご覧ください。

+0

ええ、物事を過度に複雑にするのはなぜですか?ギャップのない数値キーが必要な場合は、実行時にサイズが分かっている場合は 'std :: array'を、そうでない場合は' vector'を使用してください。あなたのキーが組み込まれています。このために連想型のコンテナを使用すると、ホイールを再発明していますが、正方形にしています。 –

関連する問題