簡體   English   中英

STL地圖插入效率:[]與插入

[英]STL map insertion efficiency: [] vs. insert

地圖插入有兩種方式:

m[key] = val;

要么

m.insert(make_pair(key, val));

我的問題是,哪個操作更快? 人們通常說第一個較慢,因為如果'key'在map中不存在,STL Standard首先'插入'一個默認元素,然后將'val'分配給默認元素。

但由於'make_pair',我沒有看到第二種方式更好。 pair<T1, T2>(key, val)相比,make_pair實際上是一種方便的方式來進行'對'。 無論如何,他們都做了兩個任務,一個是將'key'分配給'pair.first',兩個分配'val'給'pair.second'。 完成配對后,map將插入由'pair.second'初始化的元素。

所以第一種方法是default construct of typeof(val) '的default construct of typeof(val) 2.賦值第二種方式是1.賦值copy construct of typeof(val)copy construct of typeof(val) '

兩者都有不同的結論。

m[key] = val;

如果key不存在,將插入新的鍵值對,否則它將覆蓋映射到key的舊值(如果key已經存在)。

m.insert(make_pair(key, val));

只有當key還不存在時才會插入該對,它永遠不會覆蓋舊值。 因此,相應地選擇您想要完成的任務。
對於更有效的問題:個人資料。 :P可能是我說的第一種方式。 賦值(又名副本)是兩種方式的情況,所以唯一的區別在於構造。 眾所周知並且應該實現,默認構造基本上應該是無操作,因此非常有效。 副本就是 - 副本。 因此,我們得到一個“無操作”和一個副本,然后我們得到兩個副本。
編輯 :最后,相信您的分析告訴您的內容。 我的分析就像@Matthieu在他的評論中提到的那樣,但那是我的猜測。 :)


然后,我們有C ++ 0x,而第二種方式的雙重拷貝將是無效的,因為現在可以簡單地移動該對。 所以最后,我認為它回到了我的第一點:用正確的方法來完成你想要做的事情。

在具有充足內存的輕載系統上,此代碼:

#include <map>
#include <iostream>
#include <ctime>
#include <string>

using namespace std;

typedef map <unsigned int,string> MapType;
const unsigned int NINSERTS = 1000000;

int main() {
    MapType m1;
    string s = "foobar";
    clock_t t = clock();
    for ( unsigned int i = 0; i < NINSERTS; i++ ) {
        m1[i] = s;
    }
    cout << clock() - t << endl;
    MapType m2;
    t = clock();
    for ( unsigned int i = 0; i < NINSERTS; i++ ) {
        m2.insert( make_pair( i, s ) );
    }
    cout << clock() - t << endl;
}

生產:

1547
1453

或重復運行時的類似值。 因此插入(在這種情況下)略快。

表現明智我認為它們大致相同。 對於具有大對象的地圖,可能存在一些例外情況,在這種情況下,您應該使用[]或者使用emplace來創建比“insert”更少的臨時對象。 詳情請參見此處的討論。

但是,如果在插入運算符上使用“提示”功能,則可以在特殊情況下獲得性能提升。 那么,從這里看選項2

iterator insert (const_iterator position, const value_type& val);

如果你提供了一個很好的提示,那么'insert'操作可以減少到恆定的時間(從log(n)開始)(如果你知道你在地圖后面添加東西的話)。

我們必須通過提及相對性能取決於被復制對象的類型(大小)來改進分析。

我用(int - > set)的映射做了類似的實驗(到nbt)。 我知道這是一件可怕的事情,但是,這個場景的說明。 “值”,在這種情況下是一組整數,其中包含20個元素。

我執行了[] = Vs的一百萬次迭代。 插入操作並執行RDTSC / iter-count。

[] =設置| 10731個周期

insert(make_pair <>)| 26100個周期

它顯示了由於復制而增加的懲罰幅度。 當然,CPP11(移動ctor's)將改變畫面。

我接受它:值得提醒的是,map是一個平衡的二叉樹,大多數修改和檢查都需要O(logN)。

真的取決於你想要解決的問題。

1)如果你只是想知道它還沒有插入值,那么[]會做兩件事:a)檢查項目是否存在b)如果不存在則會創建對並執行什么插入做(O(logN)的雙重工作),所以我會使用插入。

2)如果你不確定它是否存在,那么a)如果你確實通過像if(map.find(item)== mp.end())上面的幾行來檢查項目是否在那里在某處,然后使用insert,因為雙重工作[]將執行b)如果你沒有檢查,那么它取決於,因為插入不會修改值,如果它在那里,[]將,否則他們是相等的

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM