DELL Latitude D610
CPU:Pentium-M 1.73 GHz
内存:2.00GB
OS:Windows 2003
开发环境: Visual Studio 2010
编译参数:/MD /Ox /Ot /W3 /D "_CRT_SECURE_NO_WARNINGS" /D "_CRT_NONSTDC_NO_WARNINGS" /link /MACHINE:X86 kernel32.lib
测试用代码:
#include <hash_map>
#include <unordered_map>
#include <map>
#include <string>
#include <iostream>
#include <ctime>
#include <windows.h>
using namespace std;
const int TEST = 100000;
class test_cls {
public:
test_cls(){}
test_cls(const string& s1, const string& s2, const string& s3, const string& s4, int n1, int n2):
str1(s1), str2(s2), str3(s3), str4(s4), num1(n1), num2(n2){}
private:
string str1;
string str2;
string str3;
string str4;
int num1;
int num2;
};
template<typename T>
void test1(const string& test_str)
{
T t;
typedef typename T::value_type the_type;
clock_t start = clock();
for(int i = 0; i < TEST; ++i)
t.insert(the_type(i, test_cls("s1", "s2", "s3", "s4", 1, 2)));
cout << test_str << " insert:" << clock() - start << endl;
start = clock();
for(int i = 0; i < TEST; ++i)
t.find(i);
cout << test_str << " find:" << clock() - start << endl;
start = clock();
for(int i = 0; i < TEST; ++i)
t.erase(i);
cout << test_str << " erase:" << clock() - start << endl;
}
int main()
{
test1<map<int, test_cls> >("map");
::Sleep(1000);
test1<hash_map<int, test_cls> >("hash_map");
::Sleep(1000);
test1<unordered_map<int, test_cls> >("unordered_map");
return 0;
}
结果(为了减小误差,我对代码进行了10次测试):
map<int, test_cls>
次数 | 插入 | 查询 | 删除 |
1 | 125 | 15 | 78 |
2 | 125 | 15 | 63 |
3 | 125 | 15 | 63 |
4 | 125 | 15 | 63 |
5 | 109 | 16 | 78 |
6 | 109 | 16 | 78 |
7 | 125 | 15 | 78 |
8 | 125 | 15 | 78 |
9 | 125 | 15 | 63 |
10 | 125 | 15 | 78 |
hash_map<int, test_cls>
次数 | 插入 | 查询 | 删除 |
1 | 125 | 31 | 47 |
2 | 125 | 31 | 47 |
3 | 125 | 15 | 63 |
4 | 125 | 31 | 47 |
5 | 125 | 31 | 47 |
6 | 125 | 15 | 63 |
7 | 125 | 31 | 47 |
8 | 109 | 31 | 47 |
9 | 125 | 31 | 47 |
10 | 110 | 31 | 47 |
unordered_map<int, test_cls>
次数 | 插入 | 查询 | 删除 |
1 | 125 | 31 | 47 |
2 | 140 | 16 | 62 |
3 | 125 | 15 | 63 |
4 | 140 | 16 | 62 |
5 | 125 | 31 | 47 |
6 | 125 | 15 | 63 |
7 | 125 | 31 | 47 |
8 | 109 | 31 | 47 |
9 | 125 | 31 | 47 |
10 | 125 | 31 | 47 |
从上面的结果来看,map、hash_map 和 unordered_map在插入上性能差不多,但在查询上map的性能更好,而在删除上hash_map 和 unordered_map性能差不多。相比各类书籍和网上对 hash_map 和 unordered_map 与 map 的性能描述来说,似乎大相径庭。
其实这在情理之中。因为,此处使用的key类型为int,对于数值型来说(包括;char、short、long)它们在map中排序(<) 和 hash_map 和 unordered_map中的散列值计算和比较(==)都是基于基本的内置运算,效率上没什么太大差异,因此,在插入上结果几乎相同,至于在查询上,之所以map较快,也是因为它只是对key在做简单<比较,而 hash_map 和 unordered_map 却要再次计算查询量的散列值而后再做==比较。至于删除,因为map内部是会对数据进行排序的,因此,相比hash_map 和 unordered_map不排序的而言,其在删除时除了要进行查询、移除、修正外还需要对数据结构进行调整
为了验证上述结论,我将key由int改为string:
#include <hash_map>
#include <unordered_map>
#include <map>
#include <string>
#include <iostream>
#include <ctime>
#include <cstdio>
#include <windows.h>
using namespace std;
const int TEST = 100000;
class test_cls {
public:
test_cls(){}
test_cls(const string& s1, const string& s2, const string& s3, const string& s4, int n1, int n2):
str1(s1), str2(s2), str3(s3), str4(s4), num1(n1), num2(n2){}
private:
string str1;
string str2;
string str3;
string str4;
int num1;
int num2;
};
template<typename T>
void test1(const string& test_str)
{
T t;
typedef typename T::value_type the_type;
clock_t start = clock();
for(int i = 0; i < TEST; ++i)
t.insert(the_type(i, test_cls("s1", "s2", "s3", "s4", 1, 2)));
cout << test_str << " insert:" << clock() - start << endl;
start = clock();
for(int i = 0; i < TEST; ++i)
t.find(i);
cout << test_str << " find:" << clock() - start << endl;
start = clock();
for(int i = 0; i < TEST; ++i)
t.erase(i);
cout << test_str << " erase:" << clock() - start << endl;
}
template<typename T>
void test2(const string& test_str)
{
T t;
typedef typename T::value_type the_type;
string* fill_str = new string[TEST];
char tmp[10];
for(int i = 0; i < TEST; ++i)
{
sprintf(tmp, "%d", i);
fill_str[i] = tmp;
}
clock_t start = clock();
for(int i = 0; i < TEST; ++i)
t.insert(the_type(fill_str[i], test_cls("s1", "s2", "s3", "s4", 1, 2)));
cout << test_str << " insert:" << clock() - start << endl;
start = clock();
for(int i = 0; i < TEST; ++i)
t.find(fill_str[i]);
cout << test_str << " find:" << clock() - start << endl;
start = clock();
for(int i = 0; i < TEST; ++i)
t.erase(fill_str[i]);
cout << test_str << " erase:" << clock() - start << endl;
}
int main()
{
//test1<map<int, test_cls> >("map");
//::Sleep(1000);
//test1<hash_map<int, test_cls> >("hash_map");
//::Sleep(1000);
//test1<unordered_map<int, test_cls> >("unordered_map");
test2<map<string, test_cls> >("map");
::Sleep(1000);
test2<hash_map<string, test_cls> >("hash_map");
::Sleep(1000);
test2<unordered_map<string, test_cls> >("unordered_map");
return 0;
}
结果:
map<string, test_cls>
次数 | 插入 | 查询 | 删除 |
1 | 204 | 62 | 141 |
2 | 204 | 62 | 141 |
3 | 188 | 78 | 140 |
4 | 188 | 78 | 140 |
5 | 204 | 62 | 141 |
6 | 204 | 62 | 141 |
7 | 188 | 78 | 125 |
8 | 204 | 62 | 141 |
9 | 188 | 78 | 141 |
10 | 188 | 78 | 141 |
hash_map<string, test_cls>
次数 | 插入 | 查询 | 删除 |
1 | 156 | 32 | 62 |
2 | 157 | 31 | 62 |
3 | 157 | 31 | 62 |
4 | 141 | 31 | 78 |
5 | 157 | 31 | 62 |
6 | 157 | 31 | 62 |
7 | 157 | 31 | 78 |
8 | 157 | 32 | 62 |
9 | 157 | 31 | 62 |
10 | 157 | 31 | 62 |
unordered_map<string, test_cls>
次数 | 插入 | 查询 | 删除 |
1 | 141 | 31 | 47 |
2 | 141 | 16 | 62 |
3 | 141 | 15 | 63 |
4 | 157 | 15 | 63 |
5 | 141 | 16 | 62 |
6 | 141 | 31 | 47 |
7 | 157 | 31 | 47 |
8 | 157 | 15 | 63 |
9 | 141 | 31 | 47 |
10 | 141 | 16 | 62 |
因此,在选择map、hash_map 和 unordered_map 时,除了要根据实际工作需要在速度和内存方面有所抉择以外。最主要的还是要看key的类型,如果key的类型是内置的数值型的话,完全可以考虑使用map,这样就可以鱼和熊掌兼得——既可以得到很好的效率,而且不必多费内存