哈希(hash_map)快还是红黑树(map)快?

z1z2z3z4 2008-11-19 01:21:42
多数情况下我使用hash_map。以前测试速度一致只是测试查找速度,hash_map的查找速度的确是不错的。但刚才测试了hash_map删除速度,结果令人大跌眼镜。(下面贴出的伪代码,实际测试的当然是能通过编译并运行的)

//填充数据结构
struct ITEM
{
int a;
int b;
char c[50];
};
hash_map<int, ITEM> HM;

//添加
ITEM item;
for (int i=0;i<xx;i++)
{
item.a=i;
HM.insert(i, item);
}

//删除
hash_map<int, ITEM>::iterator it;
for (int i=0;i<xx;i++)
{
it = HM.find(i);
HM.erase(it);
}

测试结果:
执行数目————添加耗时————全部删除耗时——删除1项耗时
100——————4.2ms——————3.8ms——————0.078-0.081
1000——————46ms———————92ms——————0.078-0.081
10000—————482ms——————12866ms——————0.078-0.081
100000—————4619ms——————349453ms————0.078-0.081

全部删除时,是模拟实际应用,一项项地删除。
单独删除一项一般0.08毫秒,以此计算删除100000项只要8000毫秒即可,但在循环中删除却要349453毫秒。为什么循环全部删除效率这么惨?

如果用红黑树的map会不会快些?大家来谈谈。
...全文
3080 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
taodm 2008-11-19
  • 打赏
  • 举报
回复
既然内存真的够用,那,反正你的原始问题:hash和map谁快是可以有结论了。
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
我可能忽略了一个非常重要的问题:

map删除时并不是从头开始删除的。我用了一个最小堆min_heap记录元素,删除时是从min_heap取得元素key再进行删除。min_heap的排序和map不一样。

也就是说,对map删除时随机的。不是从头或从尾部删除。

我禁止删除map元素,单独操作min_heap,(10000项)占用的时间只有几十毫秒。所以上面的测试几乎都是删除map的时间。

如果从头部或尾部删除,map删除耗时非常均匀!
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
map从9000到10000突增20倍时间。
我继续测试9000和10000:

map继续测试
9000——————517ms———————787ms—————0.086-0.097======从这里元素增加10%删除耗时增加20倍
10000—————602ms——————17230ms—————0.086-0.097

我检查并确认如下信息:
系统没有运行其它任务,不运行测试时CPU占用2-5%
内存够用,物理内存512M,当填充map/hash_map后内存使用440M。
taodm 2008-11-19
  • 打赏
  • 举报
回复
你的测试精度是高的,准确度却完全没数。
hash的删除,理论最高效率O(1),最差O(N)
map的删除,具有确定的O(lgN)
在你不能排除干扰,获得如此拟合数据情况下,测试就没啥意义了。
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
补充测试10000前后的:

map测试结果
执行数目————添加耗时————全部删除耗时——删除1项耗时
100——————3.3ms——————4.6ms——————0.086-0.097
1000——————43ms———————72ms—————0.086-0.097
5000——————292ms———————459ms—————0.086-0.097
8000——————495ms———————685ms—————0.086-0.097
9000——————560ms———————846ms—————0.086-0.097======从这里元素增加10%删除耗时增加20倍
10000—————559ms——————15907ms—————0.086-0.097
100000—————7015ms——————210713ms————0.086-0.097

hash_map的测试结果放到这比较:
执行数目————添加耗时————全部删除耗时——删除1项耗时
100——————4.2ms——————3.8ms——————0.078-0.081
1000——————46ms———————92ms——————0.078-0.081======元素加10倍耗时加25倍
5000——————273ms———————2174ms—————0.086-0.097=====元素加5倍耗时加25倍
8000——————462ms———————2730ms—————0.086-0.097
9000——————497ms———————3566ms—————0.086-0.097
10000—————482ms——————12866ms——————0.078-0.081
100000—————4619ms——————349453ms————0.078-0.081
taodm 2008-11-19
  • 打赏
  • 举报
回复
认真点,map的哪平顺了,15-220-13这样的倍数变化还顺啊。
hash_map是24-140-27
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 taodm 的回复:]
哦,那为什么你对删除动作的测试结果,拟合不出曲线呢?10000时间时,结果值突跃太多了。
[/Quote]
由于hash可能存在冲突,估计在10000前后有许多元素存在冲突。
map曲线平顺得多。
hhyttppd 2008-11-19
  • 打赏
  • 举报
回复
比较stl 的map与hash_map
taodm 2008-11-19
  • 打赏
  • 举报
回复
哦,那为什么你对删除动作的测试结果,拟合不出曲线呢?10000时间时,结果值突跃太多了。
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
测试时没有其它程序在运行。不运行测试程序时windows任务管理器显示CPU占用在2-5%。在这样的情况下,现在的计时精度足够了。
WingForce 2008-11-19
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 z1z2z3z4 的回复:]
为方便我用控制台程序,没有线程。不如我测试下,用两个函数,A函数删除46次,B函数删除54次?我来测试下。。。
[/Quote]

控制台程序照样是线程,系统中总有别的线程在跑
你要测算法运行时间,在windows下要用GetThreadTimes,否则就会受到多线程干扰
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
搜索网上,很少讨论map/hash_map的删除效率的。这个话题值得探讨。
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
map试了。有记录的是:

map测试结果
执行数目————添加耗时————全部删除耗时——删除1项耗时
100——————3.3ms——————4.6ms——————0.086-0.097
1000——————43ms———————72ms—————0.086-0.097
10000—————559ms——————15907ms—————0.086-0.097
100000—————7015ms——————210713ms————0.086-0.097

hash_map的测试结果放到这比较:
执行数目————添加耗时————全部删除耗时——删除1项耗时
100——————4.2ms——————3.8ms——————0.078-0.081
1000——————46ms———————92ms——————0.078-0.081
10000—————482ms——————12866ms——————0.078-0.081
100000—————4619ms——————349453ms————0.078-0.081
taodm 2008-11-19
  • 打赏
  • 举报
回复
有这功夫还不如先试了map。
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
为方便我用控制台程序,没有线程。不如我测试下,用两个函数,A函数删除46次,B函数删除54次?我来测试下。。。
WingForce 2008-11-19
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 z1z2z3z4 的回复:]
引用 6 楼 WingForce 的回复:
其实我对你测试环境很有怀疑,你的时间是怎么计算的???能不能先说一下

时间使用rdtsc计时。用rdtsc得到CPU圈数,除以CPU频率。理论精确到纳秒级别。
[/Quote]

好的,如前所述:
[Quote=引用 5 楼 z1z2z3z4 的回复:]
在前面的46次删除中,每次删除100个耗时3-5毫秒。
在后面的删除中,每次删除100个耗时8-700毫秒。
[/Quote]
如果在前46次删除和后面的54次删除中间,发生了一次线程切换,那怎么办?
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 WingForce 的回复:]
其实我对你测试环境很有怀疑,你的时间是怎么计算的???能不能先说一下
[/Quote]
时间使用rdtsc计时。用rdtsc得到CPU圈数,除以CPU频率。理论精确到纳秒级别。
WingForce 2008-11-19
  • 打赏
  • 举报
回复
其实我对你测试环境很有怀疑,你的时间是怎么计算的???能不能先说一下
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
上面测试删除10000项耗时12866,但只删除1项只要0.08毫秒左右。
我改成在10000个元素的hash_map中每次删除100个元素,结果是:
在前面的46次删除中,每次删除100个耗时3-5毫秒。
在后面的删除中,每次删除100个耗时8-700毫秒。
z1z2z3z4 2008-11-19
  • 打赏
  • 举报
回复
说明一下,测试用的是VC内的hash_map,默认哈希。

查找的速度是很快的。我另外测试查找100000次,耗时1110毫秒。对应的删除耗时349453毫秒。不明白删除用的大量时间用到哪里了。

我主要想从应用的角度,谈谈什么时候选择hash_map,什么时候用map。如果数据需要动态地添加和删除,map会不会比hash_map更合适。
加载更多回复(3)

33,317

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 新手乐园
社区管理员
  • 新手乐园社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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