C++ 哈希封装unordered_set和unordered_map

目录

前言

封装迭代器

改良后的HashTable.h

unordered_set模拟实现代码

unordered_map模拟实现代码


前言


        unordered_map、unordered_set与map、set的区别是unoedered系列无序,除此之外功能上没有区别。但二者之间底层不同,前者底层为哈希,后者为红黑树。

      unoedered系列,并没有反向迭代器,同时通过观察源码,发现这次的const迭代器并没有复用非const迭代器:

封装迭代器


        哈希表的迭代器与其他容器的迭代器有所不同,哈希表的迭代器增加了一个 HashTable 的指针,不增加这个变量是无法完成哈希表的迭代器的,这也意味着 const 版本的迭代器需要重新写在另一个类,不能复用普通迭代器的代码完成const 迭代器

// 前置声明
template
class HashTable;

template
struct __HashTableIterator
{
	typedef HashNode Node;
	typedef __HashTableIterator self;
	typedef HashTable HT; // HashTable在这段代码下面,他找不到,报错

	Node* _node;
	HT* _pht; // HashTable的指针

	__HashTableIterator(Node* node, HT* pht)
		:_node(node)
		,_pht(pht)
	{}

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

	T* operator->() {
		return &_node->_data;
	}
	// 前置++
	self operator++() { 
		if (_node->_next) {
			_node = _node->_next;
		}
		else {
			// 如果一个桶走完了,找到下一个桶继续遍历
			KeyOfT koft;
			size_t i = _pht->HashFunc(koft(_node->_data)) % _pht->_tables.size();
			++i;
			for (i; i < _pht->_tables.size(); i++) {
				Node* cur = _pht->_tables[i];
				if (cur) {
					_node = cur;
					return* this;
				}
			}
			_node = nullptr;
		}
		return* this;

	}

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

改良后的HashTable.h

namespace OPEN_HASH2
{
	// 开散列-哈希桶

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

	// 前置声明
	template
	class HashTable;

	template
	struct __HashTableIterator
	{
		typedef HashNode Node;
		typedef __HashTableIterator self;
		typedef HashTable HT; // HashTable在这段代码下面,他找不到,报错

		Node* _node;
		HT* _pht; // HashTable的指针

		__HashTableIterator(Node* node, HT* pht)
			:_node(node)
			,_pht(pht)
		{}

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

		T* operator->() {
			return &_node->_data;
		}
		// 前置++
		self operator++() { 
			if (_node->_next) {
				_node = _node->_next;
			}
			else {
				// 如果一个桶走完了,找到下一个桶继续遍历
				KeyOfT koft;
				size_t i = _pht->HashFunc(koft(_node->_data)) % _pht->_tables.size();
				++i;
				for (i; i < _pht->_tables.size(); i++) {
					Node* cur = _pht->_tables[i];
					if (cur) {
						_node = cur;
						return* this;
					}
				}
				_node = nullptr;
			}
			return* this;

		}

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


	};


	template
	struct _Hash
	{
		const K operator()(const K& key) {
			return key;
		}
	};
	//特化
	template<>
	struct _Hash
	{
		size_t operator()(const string& key) {
			// BKDR Hash
			// https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html
			size_t hash = 0;
			for (size_t i = 0; i < key.size(); i++)
			{
				hash *= 131;//
				hash += key[i];
			}
			return hash;
		}
	};

	//struct _Hashstring
	//{
	//	size_t operator()(const string& key) {
	//		// BKDR Hash
	//		// https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html
	//		size_t hash = 0;
	//		for (size_t i = 0 ; i < key.size(); i++)
	//		{
	//			hash *= 131;//
	//			hash += key[i];
	//		}
	//		return hash;
	//	}
	//};


	template
	class HashTable
	{
		typedef HashNode Node;
	public:
		friend struct __HashTableIterator;

		typedef __HashTableIterator 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()
		{
			Clear();

		}
		void Clear() {
			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;
			}
		}

		size_t HashFunc(const K& key) {
			Hash hash;
			size_t index = hash(key);
			return index;

		}

		pair Insert(const T& data)
		{
			KeyOfT koft;
			// 如果负载因子等于1,则增容,避免大量的哈希冲突
			// 负载因子=表中数据/表的太小 衡量哈希表满的程度
			if (_tables.size() == _num)
			{
				// 1、开两倍大小的新表
				// 2、遍历旧表,重新计算在新表中位置
				// 3、释放旧表
				vector newtables;
				//size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
				// 开素数个空间提高效率
				size_t newsize = GetNextPrime(_tables.size());
				
				newtables.resize(newsize);

				for (size_t i = 0; i < _tables.size(); i++)
				{
					// 将旧表的节点取下来重新计算在新表中的位置在插入
					Node* cur = _tables[i];
					while (cur)
					{
						Node* next = cur->_next;

						size_t index = HashFunc(koft(cur->_data)) % newtables.size();
						cur->_next = newtables[index];
						newtables[index] = cur;

						cur = next;
					}
					_tables[i] = nullptr; // 旧表置空
				}
				_tables.swap(newtables);
			}

			// 计算数据在表中的映射位置
			size_t index = HashFunc(koft(data)) % _tables.size();

			// 1、先查找这个值在不在表中
			Node* cur = _tables[index];
			while (cur)
			{
				if (koft(cur->_data) == koft(data))
				{
					return make_pair(iterator(cur,this),false);
				}
				else
				{
					cur = cur->_next;
				}
			}
			// 2、头插到挂的链表中(尾插也可以)
			Node* newnode = new Node(data);

			newnode->_next = _tables[index];
			_tables[index] = newnode;
			++_num;
			return make_pair(iterator(newnode, this), true);
		}

		// 获取素数
		size_t GetNextPrime(size_t num) {
			const int PRIMECOUNT = 28; 
			static const size_t primeList[PRIMECOUNT] =
			{
				//  ul 无符号的长整型
				// 素数
				53ul,97ul,193ul,389ul,769ul, 
				1543ul,3079ul,6151ul,12289ul,24593ul,
				49157ul,98317ul,196613ul,393241ul,786433ul,
				1572869ul,3145739ul,6291469ul,12582917ul,25165843ul,
				50331653ul,100663319ul,201326611ul,402653189ul,805306457ul,
				1610612741ul,3221225473ul,4294967291ul
			};
			for (size_t i = 0; i < PRIMECOUNT; i++) {
				if (primeList[i] > num) {
					return primeList[i];
				}
			}
			return primeList[PRIMECOUNT - 1];
		}

		Node* Find(const K& key)
		{
			KeyOfT koft;
			size_t index = HashFunc(key) % _tables.szie();

			Node* cur = _tables[index];
			while (cur)
			{
				if (koft(cur->_data) == key)
				{
					return cur;
				}
				else
				{
					cur = cur->_next;
				}

			}
			return nullptr;
		}

		bool Erase(const K& key)
		{
			KeyOfT koft;
			size_t index = HashFunc(key) % _tables.size();
			Node* prev = __nullptr;

			Node* cur = _tables[index];

			while (cur)
			{
				if (koft(cur->_data) == key)
				{
					if (prev == nullptr)
					{
						// 表示要删除的在第一个结点
						_tables[index] = cur->_next;
					}
					else
					{
						prev->_next = cur->_next;
					}
					delete cur;
					return true;
				}
				else
				{
					prev = cur;
					cur = cur->_next;
				}
			}
			return false;
		}

	private:
		vector _tables; // 存的是节点的指针  指针数组
		size_t _num = 0; // 记录表中储存的数据个数

	};
}

unordered_set模拟实现代码

#include"HashTable2.h"
using namespace OPEN_HASH2; // 展开这个命名空间 不然找不到HashTable

namespace hek {

	template>
	class unordered_set {

		struct SetKOfT
		{
			const K& operator()(const K& k) {
				return k;
			}

		};
	public:
		typedef typename HashTable::iterator iterator;
		iterator begin() {
			return _ht.begin();
		}
		iterator end() {
			return _ht.end();
		}

		pair insert(const K& k) {
			return _ht.Insert(k);
		}

	private:
		HashTable _ht;
	
	};
}

unordered_map模拟实现代码

#include"HashTable2.h"
using namespace OPEN_HASH2;

namespace hek {

	template>
	class unordered_map {
		struct MapKOfT
		{
			const K& operator()(const pair& kv) {
				return kv.first;
			}
		};
	public:
		typedef typename HashTable, MapKOfT, Hash>::iterator iterator;
		iterator begin() {
			return _ht.begin();
		}
		iterator end() {
			return _ht.end();
		}

		pair insert(const pair& kv) {

			return _ht.Insert(kv);
		}

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

	private:

		HashTable, MapKOfT, Hash> _ht;

	};
}

你可能感兴趣的:(C++,哈希算法,c++,算法)