vector和map的效率簡要比較
阿新 • • 發佈:2019-01-09
專案中要對一些資料結構進行存取,而專案本身對時間延時比較敏感,在使用vector還是map上著實糾結了一番,主要某些資料量比較小,才有此糾結。
而且想搞明白,到底大到什麼資料量該用map?做了一些簡單的測試,見下。
首先,不管是vector還是map,請儘量存取指標,否則在存取時會有資料拷貝帶來不必要的時間損失。通常用int和string做key的場景比較普遍(我的專案即如此),能用int作key就用int作key,效率比string高。
測試方法:
給vector和map容器中分別塞入1,000,000個數據(順序插入,有序的),然後設定一個查詢目標,vector順序遍歷查詢,map用key查詢,對比查詢時間。使用高精度定時器計時。
基本結論:
1、unordered_map比map快
2、vector查詢14次,基本和unordered_map查詢一次耗時相當(int和string做key差別不大)
3、string作key,vector查詢100次,基本和map查詢一次耗時相當;int作key,vector查詢28次,基本和map查詢一次耗時相當
4、boost的unordered_map和map與STL的效率基本相同
因此:拋棄map,用unordered_map吧。如果明確資料量小,比如小於14個,就用vector或陣列,效率更高。
unordered_map<string,...>
unordered_map<int,...>
map<string, ...>
map<int,...>
測試程式碼:
#include <windows.h> #include <string> #include <iostream> #include <iomanip> #include <map> #include <unordered_map> #include <boost/unordered_map.hpp> #include <boost/interprocess/containers/map.hpp> #include <algorithm> using namespace std; struct MyStruct { MyStruct() {} MyStruct(int x, string s) : i(x), str(s) {} int i; string str; }; #define VECTOR_TEST_DEF std::vector<MyStruct*> //#define STRING_KEY #define MAP_TYPE std::map //#define MAP_TYPE std::unordered_map //#define MAP_TYPE boost::unordered_map //#define MAP_TYPE boost::interprocess::map #define MAP_TYPE_STR "std::map" //#define MAP_TYPE_STR "std::unordered_map" //#define MAP_TYPE_STR "boost::unordered_map" //#define MAP_TYPE_STR "boost::interprocess::map" #ifdef STRING_KEY #define MAP_TEST_DEF MAP_TYPE<string, MyStruct*> #define TARGET_VAL "100" #else #define MAP_TEST_DEF MAP_TYPE<int, MyStruct*> #define TARGET_VAL 28 #endif #define DATA_COUNT 1000000 #define LOOP_COUNT 10000 LARGE_INTEGER m_counterFreq; MyStruct* vectorRet; MyStruct* mapRet; string ToString(int d) { char szBuf[8]; sprintf_s(szBuf, "%d", d); return string(szBuf); } LONGLONG GetMicroSecCounter() { LARGE_INTEGER counter = { 0 }; QueryPerformanceCounter(&counter); return counter.QuadPart * 1000000 / m_counterFreq.QuadPart; } string GetTimeDiffMillSecStr(LONGLONG microCounterBegin, LONGLONG micoCounterEnd) { double dblDiff = (micoCounterEnd - microCounterBegin) / (double)1000; char szBuf[32]; sprintf_s(szBuf, "%.3fms", dblDiff); return szBuf; } void TestVectorMap() { VECTOR_TEST_DEF vecTest; MAP_TEST_DEF mapTest; QueryPerformanceFrequency(&m_counterFreq); vecTest.resize(DATA_COUNT); for (int i = 0; i < DATA_COUNT; i++) { string str = ToString(i); MyStruct* t = new MyStruct(i, str); vecTest[i] = t; #ifdef STRING_KEY mapTest[str] = t; #else mapTest[i] = t; #endif // STRING_KEY } LONGLONG t1 = HighPreciseTickCounter::GetMicroSecCounter(); VECTOR_TEST_DEF::iterator iterVec; for (int i = 0; i < LOOP_COUNT; i++) { iterVec = vecTest.begin(); for (; iterVec != vecTest.end(); iterVec++) { #ifdef STRING_KEY if (!strcmp((*iterVec)->str.c_str(), TARGET_VAL)) #else if ((*iterVec)->i == TARGET_VAL) #endif // STRING_KEY { vectorRet = *iterVec; break; } } } LONGLONG t2 = HighPreciseTickCounter::GetMicroSecCounter(); MAP_TEST_DEF::iterator iterMap; for (int i = 0; i < LOOP_COUNT; i++) { #ifdef STRING_KEY iterMap = mapTest.find(TARGET_VAL); #else iterMap = mapTest.find(TARGET_VAL); #endif // STRING_KEY if (iterMap != mapTest.end()) mapRet = iterMap->second; } LONGLONG t3 = HighPreciseTickCounter::GetMicroSecCounter(); #ifdef STRING_KEY string keyType = "<string, MyStruct*>"; #else string keyType = "<int, MyStruct*>"; #endif // STRING_KEY std::cout << setiosflags(ios::left); std::cout << setw(20) << "Find Target Val: " << TARGET_VAL << std::endl; std::cout << setw(20) << "Find Loop Count: " << LOOP_COUNT << std::endl; std::cout << setw(20) << "Find Cost Vector: " << GetTimeDiffMillSecStr(t1, t2) << std::endl; std::cout << setw(20) << "Find Cost Map: " << GetTimeDiffMillSecStr(t2, t3) << " " << MAP_TYPE_STR << keyType << std::endl; cout << setw(20) << "Vector Find: " << vectorRet->str << endl; cout << setw(20) << "Map Find: " << mapRet->str << endl; for (int i = 0; i < DATA_COUNT; i++) { MyStruct* t = vecTest[i]; delete t; } }