stdext::hash_set剖析,env:vs08 sp1

本文详细分析了VS2008 SP1中非标准容器stdext::hash_set的实现,包括其基于hash表的结构、插入操作以及查找效率。在插入过程中,通过计算hash值确定元素位置,并利用list作为开链存储。同时,文章探讨了负载因子超过4.0时的re-hash策略,并对比了find操作与lower_bound的区别。
摘要由CSDN通过智能技术生成


hash表对我来说是闻名不见面,因为stl提供的基于rbtree的容器目前是满足我的工作需求的。最近闲得慌,于是看看非标准(C98)容器hash_set的实现。另外我所知道使用hash表的还有MFC里的CMap,MFC的实现比较朴素,代码一看就懂,就不分析了。

源码基于VS2008 SP1。
为了表达明确,假设比较器为less<T>。


结构:

类似于基于rbtree的set、map。基于hash表的hash_set、hash_map都是提供接口的类,底层都是继承于_Hash这个模板类。最终的接口也和rbtree的实现一样,甚至insert都有重载一个hint的迭代器,尽管_Hash实际上都没用到这个迭代器。

hash表的成员讲,一般都是数组+链表指针(如MFC里的CMap)。然而hash_set用list<T>作为开链,并管理所有实际元素,用vector<list<T>::iterator>来代替传统数组做bucket。这和stl很多时候做法一致:用现有容器,而不是裸概念。如用deque实现queue,用vector+xx_heap系列函数实现priority_queue。


构造:

	void _Init(size_type _Buckets = min_buckets)
		{	// initialize hash table with _Buckets buckets, leave list alone
		_Vec.assign(_Buckets + 1, end());
		_Mask = _Buckets - 1;
		_Maxidx = _Buckets;
		}
代码比较少,主要是初始化vector的数量,和最大桶索引,其中_Mask用来取代%操作。a % (2^n) == (a & (2^n - 1))


 

insert

_Pairib insert(const value_type& _Val)
		{	// try to insert node with value _Val
		return (_Insert(_Val, end()));
		}
_Pairib _Insert(const value_type& _Val, iterator _Where)
		{	// try to insert (possibly existing) node with value _Val
		size_type _Bucket = _Hashval(this->_Kfn(_Val));
		iterator _Plist = _Get_iter_from_vec(_Vec[_Bucket + 1]);

		for (; _Plist != _Get_iter_from_vec(_Vec[_Bucket]); )
			if (this->comp(this->_Kfn(_Val), this->_Kfn(*--_Plist)))
				;	// still too high in bucket list
			else if (_Multi
				|| this->comp(this->_Kfn(*_Plist), this->_Kfn(_Val)))
				{	// found insertion point, back
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值