关于map、hash_map 和 unordered_map 的简单性能测试

测试环境:
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>

次数插入查询删除
11251578
21251563
31251563
41251563
51091678
61091678
71251578
81251578
91251563
101251578

hash_map<int, test_cls>

次数插入查询删除
11253147
21253147
31251563
41253147
51253147
61251563
71253147
81093147
91253147
101103147


unordered_map<int, test_cls>

次数插入查询删除
11253147
21401662
31251563
41401662
51253147
61251563
71253147
81093147
91253147
101253147


        从上面的结果来看,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>

次数插入查询删除
120462141
220462141
318878140
418878140
520462141
620462141
718878125
820462141
918878141
1018878141

hash_map<string, test_cls>

次数插入查询删除
11563262
21573162
31573162
41413178
51573162
61573162
71573178
81573262
91573162
101573162

unordered_map<string, test_cls>

次数插入查询删除
11413147
21411662
31411563
41571563
51411662
61413147
71573147
81571563
91413147
101411662


        因此,在选择map、hash_map 和 unordered_map 时,除了要根据实际工作需要在速度和内存方面有所抉择以外。最主要的还是要看key的类型,如果key的类型是内置的数值型的话,完全可以考虑使用map,这样就可以鱼和熊掌兼得——既可以得到很好的效率,而且不必多费内存

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值