2016-02-12 5 views
5

私はあるコードでmapを使って注文データを保存していました。巨大な地図では、破壊には時間がかかることが分かった。私が持っていたこのコードでは、10000でmapvector<pair>によって減少し、処理時間を交換...私はどのような状況std :: map <A,B>は、並べ替えられたstd :: vector <std :: pair <A,B>>より速くなりますか?

最後に、私は私がソートさvectorまたはpairmap性能を比較することを決めたので驚きました。

そして、私は状況を見つけることができなかったので、私は驚いてはどこmap他.... mapが高速であるいくつかの状況が存在しなければならない... pairvectorソート(ランダムに充填され、後にソートされた)よりも速かったですこのクラスを提供する際のポイントは何ですか?ここで

は、私がテストしたものです:

テスト1、ソート(私は、ソートのコンテナをしたいので)と破壊、map充填を比較し、vector充填対破壊:

g++ main.cpp -O3 -o mainとGOTでコンパイル
#include <iostream> 
#include <time.h> 
#include <cstdlib> 
#include <map> 
#include <vector> 
#include <algorithm> 

int main(void) 
{ 

    clock_t tStart = clock(); 

    { 
     std::map<float,int> myMap; 
     for (int i = 0; i != 10000000; ++i) 
     { 
      myMap[ ((float)std::rand())/RAND_MAX ] = i; 
     } 
    } 

    std::cout << "Time taken by map: " << ((double)(clock() - tStart)/CLOCKS_PER_SEC) << std::endl; 

    tStart = clock(); 

    { 
     std::vector< std::pair<float,int> > myVect; 
     for (int i = 0; i != 10000000; ++i) 
     { 
      myVect.push_back(std::make_pair(((float)std::rand())/RAND_MAX, i)); 
     } 

     // sort the vector, as we want a sorted container: 
     std::sort(myVect.begin(), myVect.end()); 
    } 

    std::cout << "Time taken by vect: " << ((double)(clock() - tStart)/CLOCKS_PER_SEC) << std::endl; 

    return 0; 
} 

Time taken by map: 21.7142 
Time taken by vect: 7.94725 

mapの3倍遅く...

0123その後

、私は私がテストした....「OK、ベクトルは埋めるために、より速く、ソートですが、検索がマップに速くなります」、言った:

#include <iostream> 
#include <time.h> 
#include <cstdlib> 
#include <map> 
#include <vector> 
#include <algorithm> 

int main(void) 
{ 
    clock_t tStart = clock(); 

    { 
     std::map<float,int> myMap; 
     float middle = 0; 
     float last; 
     for (int i = 0; i != 10000000; ++i) 
     { 
      last = ((float)std::rand())/RAND_MAX; 
      myMap[ last ] = i; 
      if (i == 5000000) 
       middle = last; // element we will later search 
     } 

     std::cout << "Map created after " << ((double)(clock() - tStart)/CLOCKS_PER_SEC) << std::endl; 

     float sum = 0; 
     for (int i = 0; i != 10; ++i) 
      sum += myMap[ last ]; // search it 

     std::cout << "Sum is " << sum << std::endl; 
    } 

    std::cout << "Time taken by map: " << ((double)(clock() - tStart)/CLOCKS_PER_SEC) << std::endl; 

    tStart = clock(); 

    { 
     std::vector< std::pair<float,int> > myVect; 
     std::pair<float,int> middle; 
     std::pair<float,int> last; 
     for (int i = 0; i != 10000000; ++i) 
     { 
      last = std::make_pair(((float)std::rand())/RAND_MAX, i); 
      myVect.push_back(last); 
      if (i == 5000000) 
       middle = last; // element we will later search 
     } 

     std::sort(myVect.begin(), myVect.end()); 

     std::cout << "Vector created after " << ((double)(clock() - tStart)/CLOCKS_PER_SEC) << std::endl; 

     float sum = 0; 
     for (int i = 0; i != 10; ++i) 
      sum += (std::find(myVect.begin(), myVect.end(), last))->second; // search it 

     std::cout << "Sum is " << sum << std::endl; 
    } 

    std::cout << "Time taken by vect: " << ((double)(clock() - tStart)/CLOCKS_PER_SEC) << std::endl; 

    return 0; 
} 

g++ main.cpp -O3 -o mainでコンパイルして得た:

....でも検索が vectorと明らかに速くなり
Map created after 19.5357 
Sum is 1e+08 
Time taken by map: 21.41 
Vector created after 7.96388 
Sum is 1e+08 
Time taken by vect: 8.31741 

mapで10件の検索設定は、ほぼ2秒を取り、それがvectorと半分だけ秒かかりました)

So:

  • 私は何かを見逃しましたか?
  • 私のテストは正解/正確ではありませんか?
  • mapは単純にクラスを回避するか、実際にはmapのパフォーマンスが良い状況がありますか?
+3

オペレーション間の順序を維持する必要がある場合(たとえば、挿入の間にルックアップがある場合など)、既存のコンテナに大量の挿入があります。マップにソートされたベクトルに10kのランダムな値を挿入してみてください。 –

+0

何もテストしたことがありません(例:要素の削除についてはどうすればよいですか?)。しかし、一般的には、ノードベースのデータ構造は非常にキャッシュに不相応です。 –

+0

@Revolver_Ocelot:ありがとう、それがポイントだったし、私はそれを逃した。テストをしました(下記の答えを参照してください)、そして、そうです、 'map'はついに速くなりました。 – jpo38

答えて

3

一般的に、mapは、ルックアップに散在した挿入や削除を頻繁に行うと良いでしょう。一度データ構造を構築してからルックアップだけを行うと、プロセッサのキャッシュ効果のためにソートされたvectorがほぼ確実に高速になります。ベクトルの任意の位置での挿入や削除はO(log n)ではなくO(n)であるため、これらが制限要因になる点があります。

+0

それについてはわかりません。どちらのアルゴリズムもログN時間の複雑さとログNキャッシュミスを持っています。大体同じであるかもしれない。 – usr

+0

@usrベクトルはすべてのデータが連続したアドレスに格納されています。データがキャッシュラインより小さければ、最後のカップル反復はそれから利益を受け、後の反復は次回のためにキャッシュから前の反復を押し出す可能性が低くなります。 –

+0

@ MarkRansom:説明をありがとう。私の状況では、コンテナには新しい要素が頻繁に挿入されますが、コンテナの最後には常に挿入されます(私のキーは実際にオブジェクトのタイムスタンプです)。その場合でも、 'vector'は挿入時に' map'より速く続けるでしょう。最後に、検索を最適化するための検索ではなく、バイナリ検索を使用します(ここで提案されているように:http://stackoverflow.com/questions/446296/where-can-i-get-a-useful-c-binary-search -アルゴリズム)。 – jpo38

1

std::findは、線形時間複雑さを有するが、map検索はログN複雑度を有する。

一方のアルゴリズムの方が他方のアルゴリズムの方が100000倍速いことがわかったら、疑わしくなるはずです。ベンチマークが無効です。

現実的なバリアントを比較する必要があります。おそらく、地図をバイナリ検索と比較することを意図していました。それらのバリエーションをそれぞれCPU時間の少なくとも1秒間実行して、結果を現実的に比較できるようにします。

ベンチマークが "0.00001秒"を返すと、あなたは時計の不正確なノイズにうまくいきます。この数字は何も意味しません。

関連する問題