当前位置:   article > 正文

【C++】unordered_map & unordered_set 底层刨析

【C++】unordered_map & unordered_set 底层刨析


在这里插入图片描述
C++ STL 库中,unordered_map 和 unordered_set 容器的底层为哈希表,本文将简单模拟哈希表(哈希桶),unordered_map 和 unordered_set 只需封装哈希表的接口即可实现。

1. 哈希表的改造

  1. 模板参数列表的改造

    • K:关键码类型
    • T:不同容器 T 的类型不同,如果是 unordered_map,T 代表一个键值对,如果是 unordered_set,T 为 K
    • KeyOfT:从 T 中获取 Key
    • Hash:哈希函数仿函数对象类型,哈希函数使用除留余数法,需要将 Key 转换为整型数字才能取模
    template<class K, class T, class KeyOfT, class Hash>
    class HashTable;
    
    • 1
    • 2
  2. 增加迭代器操作

    // 为了实现简单,在哈希桶的迭代器类中需要用到HashTable本身
    template<class K, class T, class KeyOfT, class Hash>
    class HashTable;
    
    // 注意:因为哈希桶在底层是单链表结构,所以哈希桶的迭代器不需要--操作
    template<class K, class T, class KeyOfT, class Hash>
    struct __HTIterator
    {
    	typedef HashNode<T> Node;
    	typedef HashTable<K, T, KeyOfT, Hash> HT;
    	typedef __HTIterator<K, T, KeyOfT, Hash> Self;
    
    	Node* _node;	// 当前迭代器关联的节点
    	HT* _ht;		// 哈希桶 - 主要是为了找下一个空桶时候方便
    
    	__HTIterator(Node* node, HT* ht)
    		: _node(node)
    		, _ht(ht)
    	{}
    
    	T& operator*()
    	{
    		return _node->_data;
    	}
    
    	Self& operator++()
    	{
    		if (_node->_next)
    		{
    			// 当前桶还是节点
    			_node = _node->_next;
    		}
    		else
    		{
    			// 当前桶走完了,找下一个桶
    			KeyOfT kot;
    			Hash hs;
    			size_t hashi = hs(kot(_node->_data)) % _ht->_tables.size();
    			
    			// 找下一个桶
    			hashi++;
    			while (hashi < _ht->_tables.size())
    			{
    				if (_ht->_tables[hashi])
    				{
    					_node = _ht->_tables[hashi];
    					break;
    				}
    				hashi++;
    			}
    
    			// 后面没有桶了
    			if (hashi == _ht->_tables.size())
    			{
    				_node = nullptr;
    			}
    		}
    		return *this;
    	}
    
    	bool operator!=(const Self& s)
    	{
    		return _node != s._node;
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
  3. 增加通过 T 获取 key 操作

    template<class K, class T, class KeyOfT, class Hash>
    class HashTable
    {
    	template<class K, class T, class KeyOfT, class Hash>
    	friend struct __HTIterator;
    
    	typedef HashNode<T> Node;
    
    public:
    	typedef __HTIterator<K, T, KeyOfT, Hash> iterator;
    
    	iterator begin()
    	{
    		for (size_t i = 0; i < _tables.size(); i++)
    		{
    			// 找到第一个桶的第一个节点
    			if (_tables[i])
    			{
    				return iterator(_tables[i], this);
    			}
    		}
    		return end();
    	}
    
    	iterator end()
    	{
    		return iterator(nullptr, this);
    	}
    
    	HashTable()
    	{
    		_tables.resize(10, nullptr);
    		_n = 0;
    	}
    
    	~HashTable()
    	{
    		for (size_t i = 0; i < _tables.size(); i++)
    		{
    			Node* cur = _tables[i];
    			while (cur)
    			{
    				Node* next = cur->_next;
    				delete cur;
    
    				cur = next;
    			}
    			_tables[i] = nullptr;
    		}
    	}
    
    	bool Insert(const T& data)
    	{
    		KeyOfT kot;
    
    		if (Find(kot(data)))
    			return false;
    
    		Hash hs;
    
    		// 负载因子到1就扩容
    		if (_n == _tables.size())
    		{
    			vector<Node*> newTables(_tables.size() * 2, nullptr);
    			for (size_t i = 0; i < _tables.size(); i++)
    			{
    				// 取出旧表中节点,重新计算挂到新表桶中
    				Node* cur = _tables[i];
    				while (cur)
    				{
    					Node* next = cur->_next;
    
    					// 头插到新表
    					size_t hashi = hs(kot(cur->_data)) % newTables.size();
    					cur->_next = newTables[hashi];
    					newTables[hashi] = cur;
    
    					cur = next;
    				}
    				_tables[i] = nullptr;
    			}
    			_tables.swap(newTables);
    		}
    
    		size_t hashi = hs(kot(data)) % _tables.size();
    		Node* newnode = new Node(data);
    
    		// 头插
    		newnode->_next = _tables[hashi];
    		_tables[hashi] = newnode;
    
    		++_n;
    		return true;
    	}
    
    	Node* Find(const K& key)
    	{
    		KeyOfT kot;
    		Hash hs;
    		size_t hashi = hs(key) % _tables.size();
    		Node* cur = _tables[hashi];
    		while (cur)
    		{
    			if (kot(cur->_data) == key)
    			{
    				return cur;
    			}
    			cur = cur->_next;
    		}
    		return nullptr;
    	}
    
    	bool Erase(const K& key)
    	{
    		KeyOfT kot;
    		Hash hs;
    		size_t hashi = hs(key) % _tables.size();
    		Node* prev = nullptr;
    		Node* cur = _tables[hashi];
    		while (cur)
    		{
    			if (kot(cur->_data) == key)
    			{
    				// 删除
    				if (prev)
    				{
    					prev->_next = cur->_next;
    				}
    				else
    				{
    					_tables[hashi] = cur->_next;
    				}
    
    				delete cur;
    
    				--_n;
    				return true;
    			}
    			prev = cur;
    			cur = cur->_next;
    		}
    		return false;
    	}
    
    private:
    	vector<Node*> _tables;	// 指针数组
    	size_t _n;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148

2. unordered_map

  • unordered_map 中存储的是 pair<K, V> 的键值对,K 为 key 的类型,V 为 value 的类型,Hash 为哈希函数类型
  • unordered_map 在实现时,只需将 HashTable 中的接口重新封装即可
template<class K, class V, class Hash = HashFunc<K>>
class unordered_map
{
	// 通过T获取key的操作
	struct MapKeyOfT
	{
		const K& operator()(const pair<K, V>& kv)
		{
			return kv.first;
		}
	};

public:
	typedef typename hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash>::iterator iterator;
		
	iterator begin()
	{
		return _ht.begin();
	}

	iterator end()
	{
		return _ht.end();
	}

	bool insert(const pair<K, V>& kv)
	{
		return _ht.Insert(kv);
	}

private:
	hash_bucket::HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

3. unordered_set

  • unordered_set 的实现类似于 unordered_map
template<class K, class Hash = HashFunc<K>>
class unordered_set
{
	struct SetKeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};

public:
	typedef typename hash_bucket::HashTable<K, const K, SetKeyOfT, Hash>::iterator iterator;

	iterator begin()
	{
		return _ht.begin();
	}

	iterator end()
	{
		return _ht.end();
	}

	bool insert(const K& key)
	{
		return _ht.Insert(key);
	}

private:
	hash_bucket::HashTable<K, const K, SetKeyOfT, Hash> _ht;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

END
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/487707
推荐阅读
相关标签
  

闽ICP备14008679号