福大軟工1816 · 第五次作業 - 結對作業2_map與unordered map的比較測試
測試代碼:
#include <iostream> using namespace std; #include <string> #include <windows.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <map> const int maxval = 2000000 * 5; #include <unordered_map> void map_test() { printf("map_test\n"); map<int, int> mp; clock_t startTime, endTime; startTime = clock(); for (int i = 0; i < maxval; i++) { mp[rand() % maxval]++; } endTime = clock(); printf("%lf\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); printf("insert finish\n"); startTime = clock(); for (int i = 0; i < maxval; i++) { if (mp.find(rand()%maxval) == mp.end()) { //printf("not found\n"); } } endTime = clock(); printf("%lf\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); printf("find finish\n"); startTime = clock(); for(auto it = mp.begin(); it!=mp.end(); it++) { } endTime = clock(); printf("%lf\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); printf("travel finish\n"); printf("------------------------------------------------\n"); } void hash_map_test() { printf("hash_map_test\n"); unordered_map<int, int> mp; clock_t startTime, endTime; startTime = clock(); for (int i = 0; i < maxval; i++) { mp[rand() % maxval] ++; } endTime = clock(); printf("%lf\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); printf("insert finish\n"); startTime = clock(); for (int i = 0; i < maxval; i++) { if (mp.find(rand() % maxval) == mp.end()) { //printf("not found\n"); } } endTime = clock(); printf("%lf\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); printf("find finish\n"); startTime = clock(); for(auto it = mp.begin(); it!=mp.end(); it++) { } endTime = clock(); printf("%lf\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); printf("travel finish\n"); printf("------------------------------------------------\n"); } int main(int argc, char *argv[]) { srand(0); map_test(); Sleep(1000); srand(0); hash_map_test(); system("pause"); return 0; }
詳解:
map(使用紅黑樹)與unordered_map(hash_map)比較
????map理論插入、查詢時間復雜度O(logn)
????unordered_map理論插入、查詢時間復雜度O(1)
數據量較小時,可能是由於unordered_map(hash_map)初始大小較小,大小頻繁到達閾值,多次重建導致插入所用時間稍大。(類似vector的重建過程)。
哈希函數也是有消耗的(應該是常數時間),這時候用於哈希的消耗大於對紅黑樹查找的消耗(O(logn)),所以unordered_map的查找時間會多余對map的查找時間。
數據量較大時,重建次數減少,用於重建的開銷小,unordered_map O(1)的優勢開始顯現
數據量更大,優勢更明顯
使用空間:
前半部分為map,後半部分為unordered_map
unordered_map占用的空間比map略多,但可以接受。
map和unordered_map內部實現應該都是采用達到閾值翻倍開辟空間的機制(16、32、64、128、256、512、1024……)浪費一定的空間是不可避免的。並且在開雙倍空間時,若不能從當前開辟,會在其他位置開辟,開好後將數據移過去。數據的頻繁移動也會消耗一定的時間,在數據量較小時尤為明顯。
一種方法是手寫定長開散列。這樣做在數據量較小時有很好地效果(避免了數據頻繁移動,真正趨近O(1))。但由於是定長的,在數據量較大時,數據重疊嚴重,散列效果急劇下降,時間復雜度趨近O(n)。
一種折中的方法是自己手寫unordered_map(hash_map),將初始大小賦為一個較大的值。擴張可以模仿STL的雙倍擴張,也可以自己采用其他方法。這樣寫出來的是最優的,但是實現起來極為麻煩。
綜合利弊,我們組采用unordered_map。
附:使用Dev測試與VS2017測試效果相差極大???
效率差了10倍???
原因:
Dev
VS2017
在Debug下,要記錄斷點等調試信息,的確慢。
Release:不對源代碼進行調試,編譯時對應用程序的速度進行優化,使得程序在代碼大小和運行速度上都是最優的。
VS2017切到release後,還更快
除了前面說的Debug與release導致效率差異外,編譯器的不同也會導致效率差異。
學到了。
福大軟工1816 · 第五次作業 - 結對作業2_map與unordered map的比較測試