C++语法(23)-- 模拟实现unordered_set和unordered_map


C++语法(22)---- 哈希表的闭散列和开散列_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130436178?spm=1001.2014.3001.5501

1.重写HashTable

由于此时我们的实现与map跟set差不多,所以需要进行调整

1.重写节点

节点通过unordered_set和unordered_map传入的东西来构造是Value类型还是pair<K,V>类型

template<class T>
struct HashNode
{
	T _data;
	HashNode<T>* _next;
	HashNode(const T& data)
	:_data(data), _next(nullptr)
	{}
};

2.重写哈希表

1.首先,一定要通过Key值查找对应的值,那么我们需要设置一个模板为K

2.我们还要传入哈希元素节点,设置模板为T(与上面一致)

3.将T的值进行哈希映射的Hash仿函数,该函数应该在unordered层传入,因为我们也不知道要映射到位置上的是什么

4.还有一个是与map和set实现一样的仿函数,用于区分到底是unordered_map还是unordered_set中的Key值的比较,该模板命名为KeyOfT

template<class K, class T, class Hash, class KeyOfT>
class HashTable
{
	typedef HashNode<T> Node;
public:
	HashTable()
		:_n(0)
	{
		_table.resize(10);
	}
	~HashTable()
	{
		//省略
	}

	bool Insert(const T& data)
	{
        //需要注意获取哈希映射的方式
        //需要用到hash转换k为对应的int再进行操作
		KeyOfT kot;
		if (Find(kot(data)) != nullptr)
			return false;

		if (_n == _table.size())
		{
			//省略怎么扩容的
		}

        //需要注意获取哈希映射的方式
        //需要用到上层传来的KeyOfT使得data变成可以被哈希映射的值
		size_t hashi = kot(data) % _table.size();

		//省略怎么插入的
	}

	Node* Find(const K& k)
	{
        //需要注意获取哈希映射的方式
        //需要用到hash转换k为对应的int再进行操作
		size_t hashi = Hash()(k) % _table.size(); 

        //省略怎么找的
	}

	bool Erase(const K& k)
	{
        //需要注意获取哈希映射的方式
        //需要用到hash转换k为对应的int再进行操作
		size_t hashi = Hash()(k) % _table.size(); 
	
        //省略怎么删除的
	}

private:
	vector<Node*> _table;
	size_t _n = 0;
};

2.unordered初步实现

1.unordered_set

对于set而言,传入的直接就是Key,那么SetOfT仿函数返回的就是key

namespace MY
{
	template<class K,class Hash = HashFunc<K>>
	class unordered_set
	{
		struct SetOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	private:
		buckethash::HashTable<K, K, Hash, SetOfT> _ht;
	};
}

2.unordered_map

对于map而言,传入的是pair,那么MapOfT仿函数返回的就是pair的first

namespace MY
{
	template<class K, class V, class Hash = HashFunc<K>>
	class unordered_map
	{
		struct MapOfT
		{
			const K& operator()(const pair<const K, V>& key)
			{
				return key.first;
			}
		};
	private:
		buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT> _ht;
	};
}

3. 哈希表的迭代器

template<class K, class T, class Hash, class KeyOfT>
struct __HTIterator
{
	typedef HashNode<T> Node;
	typedef __HTIterator<K, T, Hash, KeyOfT> Self;
	typedef HashTable<K, T, Hash, KeyOfT> HT;
	Node* _node;
	HT* _ht;
};

我们需要算到开始的位置,所以一定要传入哈希表的地址,随后访问到哈希表的tables。

扫描二维码关注公众号,回复: 15293952 查看本文章

迭代器的简单函数

__HTIterator(Node* node,HT* ht)
	:_node(node)
	,_ht(ht)
{}

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

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

bool operator != (const Self& s) const
{
	return _node != s._node;
}

重写++的实现

首先我们找到下一个位置有两种情况

1.指针往下就是下一个数

2.整个桶走完了,我们要找下一个桶有数据的位置

Self& operator++()
{
	if (_node->_next)
	{
		_node = _node->_next;
	}
	else
	{
		KeyOfT kot;
		Hash hash;
		size_t hashi = hash(kot(_node->_data)) % (_ht->_table.size());
		hashi++;
		while (hashi < _ht->_table.size())
		{
			if (_ht->_table[hashi])
			{
				_node = _ht->_table[hashi];
				break;
			}
			else
				++hashi;
		}
		if (hashi == _ht->_table.size())
		{
			_node = nullptr;
		}
	}
	return *this;
}

因为迭代器用到了哈希表,但是我将迭代器写在了哈希表的前面,所以在此之前还得先定义哈希表的前置声明

//前置声明
template<class K, class T, class Hash, class KeyOfT>
class HashTable;

 4.哈希表的迭代器形式

1.迭代器怎么才使用_table

由于哈希表中的table是私有对象,而迭代器需要访问table,那么就要将迭代器设置为哈希表的友元。

template<class K, class T, class Hash, class KeyOfT>
class HashTable
{
	typedef HashNode<T> Node;

	template<class K, class T, class Hash, class KeyOfT>
	friend struct __HTIterator; //友元

public:
	typedef __HTIterator<K, T, Hash, KeyOfT> iterator;
private:
	vector<Node*> _table;
	size_t _n = 0;
};

2.哈希表中的迭代器

需要注意的是,在迭代器中,构造函数为:

__HTIterator(Node* node,HT* ht)
	:_node(node)
	,_ht(ht)
{}

所以哈希表的函数返回包括迭代器内容的,一律需要构造迭代器返回。

_node:就是生成的节点的地址,该地址就是节点的指针,这个好获得

_ht:为哈希表的地址,那么我们在哈希表的类中,本身的对象就是_ht,我们只需要返回this

iterator begin()
{
    for (size_t i = 0; i < _table.size(); i++)
	{
		if (_table[i] != nullptr)
			return iterator(_table[i], this);
	}
	return iterator(nullptr, this);
}

iterator end()
{
	return iterator(nullptr, this);
}
iterator Find(const K& k)
{
	size_t hashi = Hash()(k) % _table.size();
	Node* cur = _table[hashi];
	KeyOfT kot;
	while (cur)
	{
		if (kot(cur->_data) == k)
			return iterator(cur, this);
		else
			cur = cur->_next;
	}
	return iterator(nullptr,this);
}

bool Erase(const K& k)
{
	size_t hashi = Hash()(k) % _table.size();
	Node* cur = _table[hashi];
	Node* prev = nullptr;
	while (cur)
	{
		if (cur->_kv.first == k)
		{
			if (cur == _table[hashi])
				_table[hashi] = cur->_next;
			else
				prev->_next = cur->_next;
			delete cur;
			_n--;
			return true;
		}
		prev = cur;
		cur = cur->_next;
	}
	return false;
}

因为需要实现map的operator[],因此insert的重写是返回一个pair类型,first是迭代器,second是bool。

pair<iterator, bool> Insert(const T& data)
{
	KeyOfT kot;
			
	iterator it = Find(kot(data));
	if (it != end())
		return make_pair(it, false);

	if (_n == _table.size())
	{
		vector<Node*> newTable;
		newTable.resize(2 * _table.size(),nullptr);
		for (int i = 0; i < _table.size(); i++)
		{
			Node* cur = _table[i];
			while (cur)
			{
				Node* next = cur->_next;
				size_t hashi = Hash()(kot(cur->_data)) % newTable.size();
				cur->_next = newTable[hashi];
				newTable[hashi] = cur;
				cur = next;
			}
			_table[i] = nullptr;
		}
				_table.swap(newTable);
	}

	size_t hashi = Hash()(kot(data)) % _table.size();
	Node* newnode = new Node(data);
	newnode->_next = _table[hashi];
	_table[hashi] = newnode;
	_n++;

	return make_pair(iterator(newnode, this), true);
}

5.unordered_map和unordered_set

	template<class K, class V, class Hash = HashFunc<K>>
	class unordered_map
	{
		struct MapOfT
		{
			const K& operator()(const pair<const K, V>& key)
			{
				return key.first;
			}
		};
	public:
		typedef typename buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT>::iterator iterator;

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

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

		iterator Find(const K& k)
		{
			return _ht.Find(k);
		}

		bool Erase(const K& k)
		{
			return _ht.Erase(k);
		}

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

		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
			return ret.first->second;
		}

	private:
		buckethash::HashTable<K, pair<const K, V>, Hash, MapOfT> _ht;
	};
	template<class K,class Hash = HashFunc<K>>
	class unordered_set
	{
		struct SetOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename buckethash::HashTable<K, K, Hash, SetOfT>::iterator iterator;

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

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

		iterator Find(const K& k)
		{
			return _ht.Find(k);
		}

		bool Erase(const K& k)
		{
			return _ht.Erase(k);
		}

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

	private:
		buckethash::HashTable<K, K, Hash, SetOfT> _ht;
	};

猜你喜欢

转载自blog.csdn.net/m0_63488627/article/details/130449452