STL关联式容器:unordered_map和unordered_set

前言

在C++98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到 O(logN),即最差情况下需要比较红黑树的高度次,当树中的结点非常多时,查询效率也不理想。

在C++11中,STL又提供了4个unordered系列的关联式容器,这四个容器与红黑树结构的关联式容器使用方式基本类似,只是其底层结构不同,本文中只对unordered_map和unordered_set进行介绍。

一:unordered_map和unordered_set

unordered_map/unordered_set顾名思义:是无序的map和set,它们与map/set的基本使用大同小异,主要区别就是底层的数据结构。

unordered_map/unordered_set与map/set的区别:

  1. map和set的底层是用红黑树实现的(O(logN),unordered_map和unordered_set底层是用哈希表实现的(O(1))。
  2. map和set可以进行排序和去重,unordered_map和unordered_set可以进行去重,但不能排序
  3. map和set是双向迭代器,unordered_map和unordered_set是单向迭代器

unordered_map/unordered_set与map/set的关联:

  1. 它们都可以实现key和key/value的搜索场景,并且功能和使用基本相同。

二:哈希桶的改造

2.1 仿函数

在模板中提供了四个模板参数:template<class K, class T, class KeyofT, class Hash>

  1. key值类型
  2. 数据类型
  3. key值的获取方法
  4. hash(key)的获取方法
2.2 key值的获取方法

需要考虑到代码复用的问题,我们需要用一个哈希桶来实现K模型的unordered_set和KV模型的unordered_map。 并且对于某些自定义类型作为参数,我们也需要考虑从它的参数中获取key值,这时就需要增加一个模板参数,来让使用者自行提供从参数中获取key值的方法。

set中key值的获取:

struct SetKeyOfValue{
   
	const K& operator()(const K& key){
   
		return key;
	}
};

map中key值的获取:

struct MapKeyOfValue{
   
	const K& operator()(const std::pair<K, V>& kv){
   
		return kv.first;
	}
};
2.3 hash(key)的转换方法

若key的类型为整型,则可以直接使用哈希函数直接进行映射。但是如果key的类型是其他的一些无法进行整型算数运算的类型或者极为庞大的数据(如常用的string或者大数等类型) 就需要一种方法来将其转换为可以计算的整型值,但是对于自定义类型我们并不能知道他的转换方法,所以就需要提供一个仿函数,让使用者自行提供转换的方法。

常用的key一般都是string和int,这里我就给了默认的整型处理方法以及string的特化方法

// 默认
template<class K>
struct _Hash{
   
	const K& operator()(const K& key){
   
		return key;
	}
};
// 特化
template<>
struct _Hash<std::string>{
   
	 size_t operator()(const std::string& key){
   
		//BKDR字符串哈希函数
		size_t hash = 0;
		for (size_t i = 0; i < key.size(); i++){
   
			hash *= 131;
			hash += key[i];
		}
		return hash;
	}
};
2.4 迭代器

如果迭代器当前所在的桶中的下一个位置不为空,则直接返回下一个位置。而如果下一个位置为空,则说明当前桶为空,就需要到下一个桶中遍历数据 。

那么我们又如何找到下一个桶的位置呢?

但是光光依靠迭代器是无法获取下一个桶的位置的,所以我就加入了一个哈希桶指针,这样就可以通过指针获取桶的哈希函数来计算出当前映射位置,再通过访问映射位置来找到下一个存有数据的桶,就可以计算出下一个位置

template<class K, class T, class KeyOfT, class Hash>
struct __HashTableIterator{
   
	typedef HashNode<T> Node;
	typedef HashBucket<K, T, KeyOfT, Hash> HB;
	typedef __HashTableIterator<K, T, KeyOfT, Hash> Self;

	__HashTableIterator(Node* node, HB* hb)
		: _node(node)
		, _phb(hb)
	{
   }

	T& operator*(){
   
		return _node->_data;
	}

	T* operator->(){
   
		return &_node->_data;
	}

	Self& operator++(){
   
		//如果下一个节点不为空,直接返回下一个
		if (_node->_next){
   
			_node = _node->_next;
		}
		//如果下一个结点为空,则走到下一个桶中
		else{
   
			//通过获取当前数据的key来判断下一个数据的位置
			KeyOfT koft;
			size_t pos = _phb->HashFunc(koft(_node->_data));
			++pos;

			for (; pos < _phb->_table.size(); pos++){
   
				Node* cur = _phb->_table[pos];
				//如果下一个桶的数据不为空,则返回桶的第一个节点
				if (cur != nullptr){
   
					_node = cur;
					return *this;
				}
			}
			//剩下的桶都没有数据
			_node = nullptr;
		}
		return *this;</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值