unordered_set,unordered_map模拟实现

前言

unordered_set和unordered_map是c++11中新增的数据结构,底层是一个哈希桶.一般来说认为查找的时间复杂度为o(1)

我们很早就在排序算法中接触过计数排序,简单回顾一下那块的哈希:开一个足够大的整形数组做哈希表,把待排序元素的值作下标,哈希表[下标]++,然后遍历哈希表,即可实现排序.

哈希桶可以理解为把整形数组改为指针数组,以链表的形式存储数据,插入改为头插,对于字符串等不支持直接转下标的类型,需要在调用时提供一些特殊接口

哈希桶

#pragma once
#include <vector>
#include <string>
#include <list>
template<class K>
struct HashFunc {								// 仿函数 可以支持任意类型的key
	size_t operator()(const K& key) {
		return (size_t)key;
	}
};
template<>
struct HashFunc<std::string> {					// 特化
	size_t operator()(const std::string& str) {
		size_t ret = 0;
		for (auto e : str) {	// 字符串哈希算法之一,挂个链接以后用了看
			ret *= 131;		//https://www.cnblogs.com/-clq/archive/2012/05/31/2528153.html
			ret += e;
		}
		return ret;
	}
};
//哈希map -----闭散链 ---- 线性探测
namespace HT {
	enum State {
		EMPTY,
		DELETE,
		EXIST
	};
	template<class K, class V>
	struct HashData {
		std::pair<K, V>_kv;	// kv
		State _state;	// 状态
		HashData() {
			_kv.first = K();
			_kv.second = V();
			_state = EMPTY;		//如果不显示写构造函数的话,必须要让EMPTY的值为0!!!
		}
	};

	template<class K, class V ,class Hash = HashFunc<K>>
	class HashTable {
		typedef HashData<K, V> HD;
	public:
		HashTable(int size = 10) {
			_tables.resize(size);
			_n = 0;
		}
		bool Insert(const std::pair<K, V>& kv) {	// 插入
			Hash hash;
			if (Find(kv.first)) {
				return false;
			}
			if (10 * _n / _tables.size() >= 7) {	//size有可能为0,这里我的选择是重写构造函数,使size有一个初始值
				dilatation();	//	负载因子超过0.7进行扩容
			}
			size_t hashi = hash(kv.first) % _tables.size();	// 找到插入下标
			while (_tables[hashi]._state == EXIST) {
				hashi++;
				hashi %= _tables.size();
			}

			_tables[hashi]._kv =kv;				// 找到了,更改哈希表的值
			_tables[hashi]._state = EXIST;
			++_n;
			return true;
		}
		HD* Find(const K key) {
			Hash hash;
			size_t hashi = hash(key) % _tables.size();	// 找到插入下标
			while (_tables[hashi]._state != EMPTY) {
				if (_tables[hashi]._state == EXIST && _tables[hashi]._kv.first == key)
				{
					return &_tables[hashi];
				}
				hashi++;
				hashi %= _tables.size();
			}
			return nullptr;
		}
		bool Earse(const K key) {
			HD* tmp = Find(key);
			if (tmp == nullptr)
				return false;
			else {
				tmp->_state = DELETE;
			}
			return true;
		}
	protected:
		void dilatation() {		// 扩容
			size_t new_size = _tables.size() * 2;
			HashTable new_HT;
			new_HT._tables.resize(new_size);
			for (auto e : _tables) {
				if (e._state == EXIST)
					new_HT.Insert(e._kv);
			}
			std::swap(_tables,new_HT._tables);
		}

	private:
		//std::vector<HashData<K, V>> _tables;
		std::vector<HD> _tables;
		size_t _n;
	};
};
namespace hash_buctet {
	template<class T>
	struct HashNode {
		T _data;
		HashNode<T>* _next;
		HashNode(const T& data)
			:_data(data)
			,_next(nullptr)
		{}
	};
	template<class K, class T, class KeyOfT, class Hash >
	class HashTable;


	
	template<class K,class T,class KeyOfT, class Hash = HashFunc<K>>
	class HashTable {
		typedef HashNode<T> Node;
		typedef HashTable<K, T,KeyOfT, Hash> HT;
	public:
		template<class Ptr, class Ref>
		struct __HTIterator
		{
			typedef HashNode<T> Node;
			typedef __HTIterator Self;

			Node* _node;
			const HashTable* _pht;

			__HTIterator(Node* node, const HashTable* pht)
				:_node(node)
				, _pht(pht)
			{}

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

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

			Self& operator++()
			{
				if (_node->_next)
				{
					// 当前桶没走完,找当前桶的下一个节点
					_node = _node->_next;
				}
				else
				{
					// 当前桶走完了,找下一个不为空的桶的第一个节点
					KeyOfT kot;
					Hash hs;
					size_t i = hs(kot(_node->_data)) % _pht->_tables.size();
					++i;
					for (; i < _pht->_tables.size(); i++)
					{
						if (_pht->_tables[i])
							break;
					}

					if (i == _pht->_tables.size())
					{
						// 所有桶都走完了,最后一个的下一个用nullptr标记
						_node = nullptr;
					}
					else
					{
						_node = _pht->_tables[i];
					}
				}

				return *this;
			}

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

		typedef __HTIterator<T*, T&> iterator;
		typedef __HTIterator<const T*, const T&> const_iterator;

		iterator begin() {
			for (size_t i = 0; i < _tables.size(); i++)
			{
				if (_tables[i] != nullptr)
					return iterator(_tables[i], this);
			}
			return end();
		}
		iterator end() {
			return iterator(nullptr, this);
		}
		const_iterator cbegin() const {
			for (size_t i = 0; i < _tables.size(); i++)
			{
				if (_tables[i] != nullptr)
					return const_iterator(_tables[i], this);
			}
			return cend();
		}
		const_iterator cend() const {
			return const_iterator(nullptr, this);
		}
		HashTable(size_t size = 10){
			_tables.resize(size);
			_n = 0;
		}
		~HashTable() {
			for (size_t i = 0; i < _tables.size(); i++) {
				Node* cur = _tables[i];
				Node* next;
				while (cur != nullptr){
					next = cur->_next;
					delete cur;
					cur = next;
				}
				_tables[i] = nullptr;
			}
			_tables.~vector();
			_n = 0;
		}
		HashTable(HT& ht) {
			*this = ht;
		}
		HT& operator=(HT& ht) {
			this->~HashTable();
			this->_tables.resize(ht._tables.size());
			for (size_t i = 0; i < ht._tables.size(); i++) {
				Node* cur = ht._tables[i];
				Node* next;
				while (cur != nullptr) {
					next = cur->_next;
					Insert(cur->_kv);
					cur = next;
				}
			}
			return *this;
		}
		std::pair<iterator,bool> Insert(const T& data)  {
			iterator ret= Find(KeyOfT()(data));
			/*ret._node = nullptr;
			ret._pht = this;*/
			if (ret._node != nullptr)
				return std::make_pair(ret, false);

			if (_n == _tables.size()) {
				dilatation();
			}

			size_t hashi = Hash()( KeyOfT()(data) ) % _tables.size();
			Node* newnode = new Node(data);
			newnode->_next = _tables[hashi];
			_tables[hashi] = newnode;
			_n++;
			return std::make_pair (iterator(newnode, this), true ) ;
		}
		iterator Find(const K key) {
			size_t hashi = Hash()(key) % _tables.size();
			Node* node = _tables[hashi];
			while (node != nullptr) {
				if (KeyOfT()(node->_data) == key) {
					return iterator(node,this);
				}
				node = node->_next;
			}
			return iterator(nullptr,this);
		}
		bool Earse(const K& key) {
			size_t hashi = Hash()(key) % _tables.size();
			Node* node = _tables[hashi];
			Node* parent = node;
			while (node != nullptr) {
				if (KeyOfT()(node->_data) == key) {
					if (parent != node) {
						parent->_next = node->_next;
					}
					else {
						_tables[hashi] = node->_next;
					}
					_n--;
					delete node;
					return true;
				}
				else {
					parent = node;
					node = node->_next;
				}
			}
			return false;
		}
	protected:
		void dilatation() {		// 扩容
			size_t newsize = _tables.size() * 2;
			HashTable newHT(newsize);				// 我这里没有去改newHT的_n,因为函数末尾直接调析构,后面不会用
			for (auto& e : _tables) {
				Node* q = e;
				Node* next;
				while (q != nullptr) {
					next = q->_next;
					newHT.protected_Insert(q);
					q =  next;
				}
				e = nullptr;
			}
			std::swap(_tables,newHT._tables);
			newHT.~HashTable();
		}
		void protected_Insert(Node* node) {					//	将整个node节点进行插入
			size_t hashi = Hash()(KeyOfT()(node->_data)) % _tables.size();
			node->_next = _tables[hashi];
			_tables[hashi] = node;
		}
	private:
		std::vector<Node*> _tables;
		size_t _n;
	};
}

封装哈希桶

unordered_set

#pragma once
#include "HsahTable.h"
namespace mystl {
	template<class K>
	struct SetKeyOfT {
		K operator()(K data)
		{
			return data;
		}
	};

	template<class K,class Hash = HashFunc<K>>
	class unordered_set {
	public:
		typedef typename hash_buctet::HashTable<K, const K, SetKeyOfT<K>, Hash>::iterator iterator;
		typedef typename hash_buctet::HashTable<K, const K, SetKeyOfT<K>, Hash>::const_iterator const_iterator;
		iterator begin() {
			return _ht.begin();
		}
		iterator end() {
			return _ht.end();
		}
		std::pair<iterator, bool> inset(const K& key) {
			return _ht.Insert(key);
		}
		bool earse(const K& key) {
			return _ht.Earse(key);
		}
		iterator find(const K& key) {
			return _ht.Find(key);
		}
		const_iterator cbegin() const{
			return _ht.cbegin();
		}
		const_iterator cend() const {
			return _ht.cend();
		}

	private:
		hash_buctet::HashTable<K,const K,SetKeyOfT<K> ,Hash> _ht;
	};
}

unordered_map

#pragma once
#include "HsahTable.h"
namespace mystl {
	template<class K, class V>
	struct MapKeyOfT {
		K operator()(const std::pair<K, V>& data)
		{
			return data.first;
		}
	};
	template<class K,class V, class Hash = HashFunc<K>>
	class unordered_map {
	public:
		typedef typename hash_buctet::HashTable<K, std::pair<const K, V>, MapKeyOfT<K,V>, Hash>::iterator iterator;
		typedef typename hash_buctet::HashTable<K, std::pair<const K, V>, MapKeyOfT<K,V>, Hash>::const_iterator const_iterator;

		iterator begin() {
			return _ht.begin();
		}
		iterator end() {
			return _ht.end();
		}
		const_iterator cbegin() const {
			return _ht.cbegin();
		}
		const_iterator cend() const {
			return _ht.cend();
		}
		std::pair<iterator, bool> inset(const std::pair<K,V>& data) {
			return _ht.Insert(data);
		}
		bool earse(const K& key) {
			return _ht.Earse(key);
		}
		iterator find(const K& key) {
			return _ht.Find(key);
		}
		V& operator[](K& key) {
			std::pair<iterator, bool> tmp = inset({ key,V() });
			return tmp.first->second;
		}
	private:
		hash_buctet::HashTable<K, std::pair<const K,V>,MapKeyOfT<K,V> > _ht;

	};
}

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-06-12 14:04:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-12 14:04:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-12 14:04:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-12 14:04:03       18 阅读

热门阅读

  1. Web前端入门必学:解锁数字世界的魔法钥匙

    2024-06-12 14:04:03       6 阅读
  2. PHP 文件上传:全面指南与最佳实践

    2024-06-12 14:04:03       8 阅读
  3. linux top 中显示swap用量并排序

    2024-06-12 14:04:03       8 阅读
  4. Redis 数据持久化策略和数据过期策略

    2024-06-12 14:04:03       6 阅读
  5. flutter EventBus

    2024-06-12 14:04:03       5 阅读
  6. 什么是前端工程化?

    2024-06-12 14:04:03       6 阅读
  7. table根据字段合并单元格

    2024-06-12 14:04:03       6 阅读
  8. vue问题记录

    2024-06-12 14:04:03       6 阅读
  9. c++多态

    c++多态

    2024-06-12 14:04:03      8 阅读
  10. 数学学习与研究//知网//简介//投稿途径?

    2024-06-12 14:04:03       6 阅读
  11. PHP Cookies:应用与管理

    2024-06-12 14:04:03       6 阅读