关于C++中的hash_map的使用

qiuzhuoxian 2010-10-19 10:04:44
本来想用hash_map实现大数量的快速查找,后来发现效率并不快,而且有些问题也很不解,比如看如下代码:

#include <iostream>
#include <hash_map.h>
using namespace std;
int main(){
hash_map<int,string> hm(3); //初始化hash_map的桶的个数
hm.insert(make_pair(0,"hello"));
hm.insert(make_pair(1,"ok"));
hm.insert(make_pair(2,"bye"));
hm.insert(make_pair(3,"world"));
cout<<hm.size()<<endl;
cout<<hm.bucket_count()<<endl;
return 0;
}

输出结果:
4
53
对这个结果很疑惑,明明我定义了桶的个数,为什么后面得到桶的个数为53?
hash_map默认对int类型的Key如何hash,hash函数是什么?
如何使得查找能更高效?可以用空间来换

各位大侠请教啊
...全文
1187 18 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
qiuzhuoxian 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 libinfei8848 的回复:]
如果你使用的vc自带的hash函数,那么它的定义中如下:

C/C++ code

template<class _Kty, class _Pr = less>
class hash_compare1
{ // traits class for hash containers
public:
//const static long lBucketSize = 0;
……
[/Quote]
我用的是GCC下的
还是不能解释为什么申请了3个空间,插入四个元素的时候,桶的个数为53
libinfei8848 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 loaden 的回复:]
引用 3 楼 taodm 的回复:

楼主才多大数据量就上hash啊?没过百万,基本意义不大。

我对hash_map<string, string> 测试的结果是,如果数据量超过1000时,hash_map就可以体现出优势。
而在小于1000时,其性能与map<string, string>非常接近。
[/Quote]
这个我的确也深有体会,在数据量较小的情况下,甚至hash效率不如map。因为hash函数对于计算字符串的hash值时间可能长于一两次数据的比较
libinfei8848 2010-10-19
  • 打赏
  • 举报
回复
如果你使用的vc自带的hash函数,那么它的定义中如下:

template<class _Kty, class _Pr = less>
class hash_compare1
{ // traits class for hash containers
public:
//const static long lBucketSize = 0;
enum
{ // parameters for hash table
bucket_size = 4, // 0 < bucket_size
min_buckets = 8 // min_buckets = 2 ^^ N, 0 < N
};
。。。

每次增长会2倍增加预分配内存,你的hash_map是哪个版本的?
luciferisnotsatan 2010-10-19
  • 打赏
  • 举报
回复
数据量小的时候,散列计算本身消耗大就体现出来了。
mapoor 2010-10-19
  • 打赏
  • 举报
回复
http://blog.sina.com.cn/s/blog_5378b2830100c5a4.html
这篇文章是 hash_map 和 map测试结果,仅供参考
qiuzhuoxian 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 loaden 的回复:]
引用 6 楼 qiuzhuoxian 的回复:

引用 4 楼 loaden 的回复:
引用 3 楼 taodm 的回复:

楼主才多大数据量就上hash啊?没过百万,基本意义不大。

我对hash_map<string, string> 测试的结果是,如果数据量超过1000时,hash_map就可以体现出优势。
而在小于1000时,其性能与map<string, string>非……
[/Quote]
这就要看里面具体如何实现的了
如果是把int的值本身做KEY的话
是不会重复
如果是对某个数取模,那么就有可能有重复。
好吧,就算没有重复,就像上面那个例子
明明申请了3个空间,也确实插入了3个元素
那为什么桶的个数为53个呢?
「已注销」 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 qiuzhuoxian 的回复:]

引用 4 楼 loaden 的回复:
引用 3 楼 taodm 的回复:

楼主才多大数据量就上hash啊?没过百万,基本意义不大。

我对hash_map<string, string> 测试的结果是,如果数据量超过1000时,hash_map就可以体现出优势。
而在小于1000时,其性能与map<string, string>非常接近。

我只是用这个例子说明遇到的问题
实……
[/Quote]
如果int作为key的话,hash_map中的key又怎么会重复呢?
Sou2012 2010-10-19
  • 打赏
  • 举报
回复
另:hash_map现在并不是STL标准库中的一员。

只不过 gcc 和 vs 都各自实现了 hash_map
qiuzhuoxian 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 loaden 的回复:]
引用 3 楼 taodm 的回复:

楼主才多大数据量就上hash啊?没过百万,基本意义不大。

我对hash_map<string, string> 测试的结果是,如果数据量超过1000时,hash_map就可以体现出优势。
而在小于1000时,其性能与map<string, string>非常接近。
[/Quote]
我只是用这个例子说明遇到的问题
实际使用中有一百多万行的数据
但是经过调试发现
在查找的过程花费的时间远大于插入的时间
于是很不解
我的想法是如果桶的个数足够大的话
那么没有冲突,查找应该是常数级别的
但是我初始化桶的个数了,发现运行完后,bucket的个数都比map.size本身大很多
所以不知道hash_map的实现到底是怎样的
Sou2012 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 loaden 的回复:]
引用 3 楼 taodm 的回复:

楼主才多大数据量就上hash啊?没过百万,基本意义不大。

我对hash_map<string, string> 测试的结果是,如果数据量超过1000时,hash_map就可以体现出优势。
而在小于1000时,其性能与map<string, string>非常接近。
[/Quote]

学习了。
「已注销」 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 taodm 的回复:]

楼主才多大数据量就上hash啊?没过百万,基本意义不大。
[/Quote]
我对hash_map<string, string> 测试的结果是,如果数据量超过1000时,hash_map就可以体现出优势。
而在小于1000时,其性能与map<string, string>非常接近。
taodm 2010-10-19
  • 打赏
  • 举报
回复
楼主才多大数据量就上hash啊?没过百万,基本意义不大。
「已注销」 2010-10-19
  • 打赏
  • 举报
回复
这是我对hash的曾经的一点尝试,仅供参考:
#include <iostream>
#include <map>
#include <string>

#ifdef __GNUC__
#include <ext/hash_map>
#else
#include <hash_map>
#endif

#ifdef __GXX_EXPERIMENTAL_CXX0X__
#include <unordered_map>
#endif

namespace std
{
using namespace __gnu_cxx;
}

namespace __gnu_cxx
{
template<> struct hash< std::string >
{
size_t operator()( const std::string& x ) const
{
return hash< const char* >()(x.c_str());
}
};
}

int main()
{
std::map<std::string, std::string> stdMap;
stdMap["_GLIBCXX_STD"] = "std";
stdMap["_GLIBCXX_BEGIN_NESTED_NAMESPACE"] = "+namespace";
stdMap["_GLIBCXX_BEGIN_NAMESPACE"] = "+namespace";
stdMap["_GLIBCXX_END_NESTED_NAMESPACE"] = "}";
stdMap["_GLIBCXX_END_NAMESPACE"] = "}";
stdMap["_GLIBCXX_END_NAMESPACE_TR1"] = "}";
stdMap["_GLIBCXX_BEGIN_NAMESPACE_TR1"] = "-namespace tr1 {";
stdMap["_GLIBCXX_STD2"] = "2std";
stdMap["_GLIBCXX_BEGIN_NESTED_NAMESPACE2"] = "2+namespace";
stdMap["_GLIBCXX_BEGIN_NAMESPACE2"] = "2+namespace";
stdMap["_GLIBCXX_END_NESTED_NAMESPACE2"] = "2}";
stdMap["_GLIBCXX_END_NAMESPACE2"] = "2}";
stdMap["_GLIBCXX_END_NAMESPACE_TR12"] = "2}";
stdMap["_GLIBCXX_BEGIN_NAMESPACE_TR12"] = "2-namespace tr1 {";
stdMap["_XXGLIBCXX_END_NAMESPACE_TR12"] = "X2}";
stdMap["_XXGLIBCXX_BEGIN_NAMESPACE_TR12"] = "X2-namespace tr1 {";

std::hash_map<std::string, std::string> hashMap;
hashMap["_GLIBCXX_STD"] = "std";
hashMap["_GLIBCXX_BEGIN_NESTED_NAMESPACE"] = "+namespace";
hashMap["_GLIBCXX_BEGIN_NAMESPACE"] = "+namespace";
hashMap["_GLIBCXX_END_NESTED_NAMESPACE"] = "}";
hashMap["_GLIBCXX_END_NAMESPACE"] = "}";
hashMap["_GLIBCXX_END_NAMESPACE_TR1"] = "}";
hashMap["_GLIBCXX_BEGIN_NAMESPACE_TR1"] = "-namespace tr1 {";
hashMap["_GLIBCXX_STD2"] = "2std";
hashMap["_GLIBCXX_BEGIN_NESTED_NAMESPACE2"] = "2+namespace";
hashMap["_GLIBCXX_BEGIN_NAMESPACE2"] = "2+namespace";
hashMap["_GLIBCXX_END_NESTED_NAMESPACE2"] = "2}";
hashMap["_GLIBCXX_END_NAMESPACE2"] = "2}";
hashMap["_GLIBCXX_END_NAMESPACE_TR12"] = "2}";
hashMap["_GLIBCXX_BEGIN_NAMESPACE_TR12"] = "2-namespace tr1 {";
hashMap["_XXGLIBCXX_END_NAMESPACE_TR12"] = "X2}";
hashMap["_XXGLIBCXX_BEGIN_NAMESPACE_TR12"] = "X2-namespace tr1 {";

#ifdef __GXX_EXPERIMENTAL_CXX0X__
std::unordered_map<std::string, std::string> unorderedMap;
unorderedMap["_GLIBCXX_STD"] = "std";
unorderedMap["_GLIBCXX_BEGIN_NESTED_NAMESPACE"] = "+namespace";
unorderedMap["_GLIBCXX_BEGIN_NAMESPACE"] = "+namespace";
unorderedMap["_GLIBCXX_END_NESTED_NAMESPACE"] = "}";
unorderedMap["_GLIBCXX_END_NAMESPACE"] = "}";
unorderedMap["_GLIBCXX_END_NAMESPACE_TR1"] = "}";
unorderedMap["_GLIBCXX_BEGIN_NAMESPACE_TR1"] = "-namespace tr1 {";
unorderedMap["_GLIBCXX_STD2"] = "2std";
unorderedMap["_GLIBCXX_BEGIN_NESTED_NAMESPACE2"] = "2+namespace";
unorderedMap["_GLIBCXX_BEGIN_NAMESPACE2"] = "2+namespace";
unorderedMap["_GLIBCXX_END_NESTED_NAMESPACE2"] = "2}";
unorderedMap["_GLIBCXX_END_NAMESPACE2"] = "2}";
unorderedMap["_GLIBCXX_END_NAMESPACE_TR12"] = "2}";
unorderedMap["_GLIBCXX_BEGIN_NAMESPACE_TR12"] = "2-namespace tr1 {";
unorderedMap["_XXGLIBCXX_END_NAMESPACE_TR12"] = "X2}";
unorderedMap["_XXGLIBCXX_BEGIN_NAMESPACE_TR12"] = "X2-namespace tr1 {";
#endif

for (int i = 0; i < 5; ++i)
{
const clock_t t = clock();
for (int j = 0; j < 1000000; ++j) stdMap.find("testfindkey");
std::cout << "stdMap " << i + 1 << " : " << clock() - t << std::endl;
}

std::cout << "\n---------------\n" << std::endl;

for (int i = 0; i < 5; ++i)
{
const clock_t t = clock();
for (int j = 0; j < 1000000; ++j) hashMap.find("testfindkey");
std::cout << "hashMap " << i + 1 << " : " << clock() - t << std::endl;
}

#ifdef __GXX_EXPERIMENTAL_CXX0X__
std::cout << "\n---------------\n" << std::endl;

for (int i = 0; i < 5; ++i)
{
const clock_t t = clock();
for (int j = 0; j < 1000000; ++j) unorderedMap.find("testfindkey");
std::cout << "unorderedMap " << i + 1 << " : " << clock() - t << std::endl;
}
#endif

return 0;
}

「已注销」 2010-10-19
  • 打赏
  • 举报
回复
对于int类型的key,使用hash还有意义吗?
hai040 2010-10-19
  • 打赏
  • 举报
回复
你插了4个
另外是要时间还是空间?
纠结于占了多少空间干什么?
ww884203 2010-10-19
  • 打赏
  • 举报
回复
学习了。。。。
越发觉得自己的无知
  • 打赏
  • 举报
回复
hash_map基于hash表(哈希表)实现,简单的说仅适用于数据量非常巨大的情况下。

一般情况下hash_map检索效率低于map(基于红黑树实现)。
xiangchendub 2010-10-19
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 libinfei8848 的回复:]

引用 4 楼 loaden 的回复:
引用 3 楼 taodm 的回复:

楼主才多大数据量就上hash啊?没过百万,基本意义不大。

我对hash_map<string, string> 测试的结果是,如果数据量超过1000时,hash_map就可以体现出优势。
而在小于1000时,其性能与map<string, string>非常接近。

这个我的确也深有体会,在数据量较小的……
[/Quote]

+1

65,184

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧