VS2010 STL hashmap

44 篇文章 1 订阅
16 篇文章 0 订阅

版本是 V5.20:0009

hashmap继承于_Hash,基本所有实现都是对于_Hash得封装。这里主要是阅读一下_Hash的代码流程。


首先是hash_map声明

template<class _Kty,
	class _Ty,
	class _Tr = hash_compare<_Kty, less<_Kty> >,
	class _Alloc = allocator<pair<const _Kty, _Ty> > >
	class hash_map
		: public _Hash<_Hmap_traits<_Kty, _Ty, _Tr, _Alloc, false> >

后面是_Hash的内容概要。

其存储结构:

一个std::list用来存储Pair数据,

一个Vector用来存储_Hash的Bucket信息(Bucket Begin和Bucket End. 其实就是list里面的iterator。)一个Bucket的数据是在list里面的连续的一段,顺序存储。判定方式通过less方法类来判定。

_Mask是当前索引的掩码

_Maxidx:是当前的索引个数,或者说是Bucket个数。_Mask = _Maxidx - 1;

_Max_bucket_size:当前的Hash表的负载率。默认是1.0。也就是当前的List.size() / _Maxidx如果比该值大就会进行Hash表扩容。这是一个很耗时的过程。

		// TEMPLATE CLASS _Hash
template<class _Traits>
	class _Hash
		: public _Traits	// traits serves as base class
{
	typedef list<typename _Traits::value_type,
		typename _Traits::allocator_type> _Mylist;
	typedef vector<iterator,
		typename allocator_type::template
			rebind<iterator>::other> _Myvec;	
	...
	
	_Mylist _List;	// list of elements, must initialize before _Vec
	_Myvec _Vec;	// vector of list iterators, begin() then end()-1
	size_type _Mask;	// the key mask
	size_type _Maxidx;	// current maximum key value
	float _Max_bucket_size;	// current maximum bucket size
}	

接着看看Hash数据的插入过程

// 如果插入的是已经存在key的内容,则插入失败,返回已有的key的内容
	_Pairib _Insert(const value_type& _Val, iterator _Plist)
		{	// try to insert existing node with value _Val
		
		// 计算Hash Index的过程。里面使用了comp的operator()操作
		size_type _Bucket = _Hashval(this->_Kfn(_Val));
		
		// 获取Bucket的结束指针。第一个元素的时候会_Begin(_Bucket)和_End(_Bucket)内容相同
		iterator _Where = _End(_Bucket);

		// 这个线性算法保证在同一个bucket的内容是从小到大。
		// 选择一个where使得当前元素插入在where之前
		for (; _Where != _Begin(_Bucket); )
			if (this->comp(this->_Kfn(_Val), this->_Kfn(*--_Where)))
				;	// still too high in bucket list
				// 如果key比较小,就继续往前推算,直到Begin
			else if (_Multi
				|| this->comp(this->_Kfn(*_Where), this->_Kfn(_Val)))
				{	// found insertion point, back up to it
				// 当前key比where的key要大或者等,则选择where的后面插入
				++_Where;
				break;
				}
			else
				{	
				// discard new list element and return existing
				// Key完全相等,丢弃
				_List.erase(_Plist);
				return (_Pairib(_Where, false));
				}
		
		// List的当前插入数据的iterator. 对于vector和list进行了插入删除等操作,其他元素的iterator仍然有效
		iterator _Next = _Plist;
		
		// 如果where正好在当前元素之后,无需进行顺序调整
		if (_Where != ++_Next)
			// 不知道为什么使用_Splice_same而不是用splice
			_List._Splice_same(_Where, _List,
				_Plist, _Next, 1);	// move element into place
		
		// 进行桶数据修正
		_Insert_bucket(_Plist, _Where, _Bucket);
		
		// 进行桶扩容
		_Check_size();
		
		// 返回当前的映射数据
		return (_Pairib(_Plist, true));	// return iterator for new element
		}

Hash索引计算算法:

	// 计算实际key的过程
	size_type _Hashval(const key_type& _Keyval) const
		{	// return hash value, masked and wrapped to current table size
		size_type _Num = this->comp(_Keyval) & _Mask;
		if (_Maxidx <= _Num)
			_Num -= (_Mask >> 1) + 1;
		return (_Num);
		}

_Hash的vector管理过程

	// 桶插入代码
	void _Insert_bucket(iterator _Plist, iterator _Where,
		size_type _Bucket)
		{	// fix iterators after inserting _Plist before _Where
		if (_Vec_lo(_Bucket) == end())
		// 插入空桶
			{	// make bucket non-empty
			_Vec_lo(_Bucket) = _Plist;
			_Vec_hi(_Bucket) = _Plist;
			}
		else if (_Vec_lo(_Bucket) == _Where)
		// 元素插到桶头
			_Vec_lo(_Bucket) = _Plist;	// move beginning back one element
		else if (++_Vec_hi(_Bucket) != _Plist)	// move end up one element
		// 如果插入到桶尾,则直接把桶尾++
		// 否则则桶尾恢复
			--_Vec_hi(_Bucket);	// or not
		}

表扩充流程,其实就是所有当前元素的重新插入过程:

	// 进行表扩充
	void _Check_size()
		{	// grow table as needed
		if (max_load_factor() < load_factor())

 #if _HAS_INCREMENTAL_HASH
			_Grow();	// too dense, need to grow hash table

 #else /* _HAS_INCREMENTAL_HASH */
			{	// rehash to bigger table
			size_type _Maxsize = _Vec.max_size() / 2;
			size_type _Newsize = bucket_count();

			for (int _Idx = 0; _Idx < 3 && _Newsize < _Maxsize; ++_Idx)
				_Newsize *= 2;	// multiply safely by 8
			_Init(_Newsize);
			_Reinsert(end());
			}
 #endif /* _HAS_INCREMENTAL_HASH */
		}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值