用哈希表封装myunordered_map和myunordered_set

结构上hash_map和hash_set跟map和set的完全类似,复用同一个hashtable实现key和key/value结构,hash_set传给hash_table的是两个key,hash_map传给hash_table的是pair<const key, value>


2. 模拟实现unordered_map和unordered_set
2.1 实现出复用哈希表的框架,并支持insert        

• key参数就用K,value参数就用V,哈希表中的数据类型在哈希表层并不知道是key还是pair<const key, value>,因此还是利用泛型的思想,我们使用T。

• 其次跟map和set相比而言unordered_map和unordered_set的模拟实现类结构更复杂一点,但是
大框架和思路是完全类似的。因为HashTable实现了泛型不知道T参数导致是K,还是pair<K,V>,
那么insert内部进行插入时要用K对象转换成整形取模和K比较相等,因为pair的value不参与计算取
模,且默认支持的是key和value一起比较相等,我们需要时的任何时候只需要比较K对象,所以我们在unordered_map和unordered_set层分别实现⼀个MapKeyOfT和SetKeyOfT的仿函数传给
HashTable的KeyOfT,然后HashTable中通过KeyOfT仿函数取出T类型对象中的K对象,再通过仿函数Hash给key转为整型支持取模。

// MyUnorderedSet.h
namespace kk
{
    template<class K, class Hash = HashFunc<K>>
    class unordered_set
    {
        struct SetKeyOfT
        {
            const K& operator()(const K& key)
            {
                return key;
            }
        };
    public:
        bool insert(const K& key)
        {
            return _ht.Insert(key);
        }
    private:
        hash_bucket::HashTable<K, K, SetKeyOfT, Hash> _ht;
    };
}

// MyUnorderedMap.h
namespace kk
{
    template<class K, class V, class Hash = HashFunc<K>>
    class unordered_map
    {
        struct MapKeyOfT
        {
            const K& operator()(const pair<K, V>& kv)
            {
                return kv.first;
            }
        };
    public:
        bool insert(const pair<K, V>& kv)
        {
            return _ht.Insert(kv);
        }
    private:
        hash_bucket::HashTable<K, pair<K, V>, MapKeyOfT, Hash> _ht;
    };
}

// HashTable.h
template<class K>
struct HashFunc
{
    size_t operator()(const K& key)
    {
        return (size_t)key;
    }
};

namespace hash_bucket
{
    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
    {
        typedef HashNode<T> Node;
        inline unsigned long __stl_next_prime(unsigned long n)
        {
            static const int __stl_num_primes = 28;
            static const unsigned long __stl_prime_list[__stl_num_primes] =
            {
                53, 97, 193, 389, 769,
                1543, 3079, 6151, 12289, 24593,
                49157, 98317, 196613, 393241, 786433,
                1572869, 3145739, 6291469, 12582917, 25165843,
                50331653, 100663319, 201326611, 402653189, 805306457,
                1610612741, 3221225473, 4294967291
            };
            const unsigned long* first = __stl_prime_list;
            const unsigned long* last = __stl_prime_list + __stl_num_primes;
            const unsigned long* pos = lower_bound(first, last, n);
            return pos == last ? *(last - 1) : *pos;
        }
        public:
        HashTable()
        {
            _tables.resize(__stl_next_prime(_tables.size()), nullptr);
        }
        ~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;
            size_t hashi = hs(kot(data)) % _tables.size();// 负载因⼦==1扩容
            if (_n == _tables.size())
            {
                vector<Node*> newtables(__stl_next_prime(_tables.size()),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);
            }// 头插
            Node* newnode = new Node(data);
            newnode->_next = _tables[hashi];
            _tables[hashi] = newnode;
            ++_n;
            return true;
        }
    private:
        vector<Node*> _tables;// 指针数组
        size_t _n = 0;// 表中存储数据个数
    };
}

支持iterator的实现

iterator实现思路分析
• iterator实现的大框架跟map/set的iterator思路是一致的,用一个类型封装结点的指针,再通过重载运算符实现,迭代器像指针一样访问的行为,要注意的是哈希表的迭代器是单向迭代器
• 这里的难点是operator++的实现。iterator中有一个指向结点的指针,如果当前桶下面还有结点,
则结点的指针指向下一个结点即可。如果当前桶走完了,则需要想办法计算找到下一个桶。这里的难点是反而是结构设计的问题,所以iterator中除了有结点的指针,还有哈希表对象的指针,这样当前桶走完了,要计算下一个桶就相对容易多了,用key值计算出当前桶位置,依次往后找下一个不为空的桶即可。因为是单向迭代器,所以不支持operator--。
• begin()返回第一个桶中第一个节点指针构造的迭代器,这里end()返回迭代器可以用空表示。
• unordered_set的iterator不支持修改,我们把unordered_set的第二个模板参数改成const K即
可, HashTable<K, const K, SetKeyOfT, Hash> _ht;
• unordered_map的iterator也不支持修改key但是可以修改value,我们把unordered_map的第二个
模板参数pair的第一个参数改成const K即可, HashTable<K, pair<const K, V>, MapKeyOfT, Hash> _ht;
• 另外,由于迭代器需要哈希表的指针来访问表,因此需要将迭代器设置为哈希表的友元类。哈希表需要typedef迭代器,迭代器有需要使用哈希表指针,因此两个类产生了相互依赖,编译器在找类的时候只会向上寻找,因此两个类谁放在前面都会使得另一个类找不到后面的类。因此我们把迭代器定义在前面,哈希表定义在后面,并在迭代器之前加上前置声明来解决这个问题

• 由于迭代器中使用了哈希表指针,因此迭代器中还需要多传一个模板参数K。

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 Ref,class Ptr,class KeyOfT,class Hash>
struct HTIterator
{
	typedef HashNode<T> Node;
	typedef HashTable<K, T, KeyOfT, Hash> HT;
	typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;

	Node* _node;
	const HT* _ht;

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

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

	Self operator++(int)
	{
		Self tmp = *this;
		++(*this);
		return tmp;
	} 

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

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

对于unordered_map,我们还需要重载[],unordered_map的[]有两种情况,如果key不存在,就插入,并返回插入后value的引用,如果key存在,则插入失败,充当查找功能,返回value的引用。

V& operator[](const K& key)
{
	pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
	//it.first是一个迭代器,使用->解引用得到_data,而map传给T为pair<K,V>类型,隐藏了第二层
	//pair取second的->
	return ret.first->second;
}

完整代码实现

//Unordered_Set.h
#pragma once
#include"HashTable.h"

namespace hj
{
	template<class K,class Hash = HashFunc<K>>
	class unordered_set
	{
		struct UnorderedSetKeyOfT
		{
			const K& operator()(const K& key)
			{
				return key;
			}
		};
	public:
		typedef typename hash_bucket::HashTable<K, const K, UnorderedSetKeyOfT, Hash>::Iterator iterator;
		typedef typename hash_bucket::HashTable<K, const K, UnorderedSetKeyOfT, Hash>::ConstIterator const_iterator;

		iterator begin()
		{
			return _ht.Begin();
		}
		iterator end()
		{
			return _ht.End();
		}
		const_iterator begin() const
		{
			return _ht.Begin();
		}
		const_iterator end() const
		{
			return _ht.End();
		}
		bool empty() const
		{
			return _ht.Empty();
		}
		size_t size() const
		{
			return _ht.Size();
		}
		pair<iterator, bool> insert(const K& key)
		{
			return _ht.Insert(key);
		}
		iterator Erase(const K& key)
		{
			return _ht.Erase(key);
		}
		iterator Find(const K& key)
		{
			return _ht.Find(key);
		}
	private:
		hash_bucket::HashTable<K, const K, UnorderedSetKeyOfT, Hash> _ht;
	};
}


//Unordered_Map.h
#pragma once
#include"HashTable.h"

namespace hj
{
	template<class K, class V,class Hash = HashFunc<K>>
	class unordered_map
	{
		struct UnorderedMapKeyOfT
		{
			const K& operator()(const pair<const K,V>& kv)
			{
				return kv.first;
			}
		};
	public:
		typedef typename hash_bucket::HashTable<K, pair<const K, V>, UnorderedMapKeyOfT, Hash>::Iterator iterator;
		typedef typename hash_bucket::HashTable<K, pair<const K, V>, UnorderedMapKeyOfT, Hash>::ConstIterator const_iterator;

		iterator begin()
		{
			return _ht.Begin();
		}
		iterator end()
		{
			return _ht.End();
		}
		const_iterator begin() const
		{
			return _ht.Begin();
		}
		const_iterator end() const
		{
			return _ht.End();
		}
		bool empty() const
		{
			return _ht.Empty();
		}
		size_t size() const
		{
			return _ht.Size();
		}
		pair<iterator, bool> insert(const pair<K,V>& kv)
		{
			return _ht.Insert(kv);
		}
		iterator Erase(const K& key)
		{
			return _ht.Erase(key);
		}
		iterator Find(const K& key)
		{
			return _ht.Find(key);
		}
		V& operator[](const K& key)
		{
			pair<iterator, bool> ret = _ht.Insert(make_pair(key, V()));
			//it.first是一个迭代器,使用->解引用得到_data,而map传给T为pair<K,V>类型,隐藏了第二层
			//pair取second的->
			return ret.first->second;
		}
	private:
		hash_bucket::HashTable<K, pair<const K,V>, UnorderedMapKeyOfT, Hash> _ht;
	};
}


//HashTable.h
#pragma once
#include<vector>
#include<iostream>
#include<string>
using namespace std;
template<class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};

template<>
struct HashFunc<string>
{
	size_t operator()(const string& s)
	{
		size_t val = 0;
		for (auto& ch : s)
		{
			val *= 131;
			val += ch;
		}
		return val;
	}
};

static inline unsigned long __stl_next_prime(unsigned long n)
{
	// Note: assumes long is at least 32 bits.
	static const int __stl_num_primes = 28;
	static const unsigned long __stl_prime_list[__stl_num_primes] = {
		53, 97, 193, 389, 769,
		1543, 3079, 6151, 12289, 24593,
		49157, 98317, 196613, 393241, 786433,
		1572869, 3145739, 6291469, 12582917, 25165843,
		50331653, 100663319, 201326611, 402653189, 805306457,
		1610612741, 3221225473, 4294967291
	};
	const unsigned long* first = __stl_prime_list;
	const unsigned long* last = __stl_prime_list + __stl_num_primes;
	const unsigned long* pos = lower_bound(first, last, n);
	return pos == last ? *(last - 1) : *pos;
}

namespace hash_bucket
{
	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 Ref,class Ptr,class KeyOfT,class Hash>
	struct HTIterator
	{
		typedef HashNode<T> Node;
		typedef HashTable<K, T, KeyOfT, Hash> HT;
		typedef HTIterator<K, T, Ref, Ptr, KeyOfT, Hash> Self;

		Node* _node;
		const HT* _ht;

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

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

		Self operator++(int)
		{
			Self tmp = *this;
			++(*this);
			return tmp;
		} 

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

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

	template<class K, class T, class KeyOfT, class Hash>
	class HashTable
	{
		template<class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
		friend struct HTIterator;

		typedef HashNode<T> Node;
	public:
		typedef HTIterator<K, T, T&, T*, KeyOfT, Hash> Iterator;
		typedef HTIterator<K, T, const T&, const T*, KeyOfT, Hash> ConstIterator;

		HashTable(size_t capacity = 0)
			:_n(0)
		{
			_tables.resize(__stl_next_prime(capacity), nullptr);
		}

		~HashTable()
		{
			for (auto& data : _tables)
			{
				if (data)
				{
					Node* cur = data;
					while (cur)
					{
						Node* next = cur->_next;
						delete cur;
						cur = next;
					}
				}
				data = nullptr;
			}
			_n = 0;
		}

		Iterator Begin()
		{
			for (int i = 0; i < _tables.size(); i++)
			{
				if(_tables[i])
				{
					return Iterator(_tables[i], this);
				}
			}
			//如果表为空 返回End
			return End();
		}

		ConstIterator Begin() const
		{
			for (int i = 0; i < _tables.size(); i++)
			{
				if (_tables[i])
				{
					return ConstIterator(_tables[i], this);
				}
			}
			//如果表为空 返回End
			return End();
		}

		Iterator End()
		{
			return Iterator(nullptr, this);
		}

		ConstIterator End() const
		{
			return ConstIterator(nullptr, this);
		}

		pair<Iterator,bool> Insert(const T& data)
		{
			KeyOfT kot;
			Iterator it = Find(kot(data));
			if (it != End())
				return make_pair(it, false);
			if (_n == _tables.size())
			{
				Rehash(__stl_next_prime(_tables.size() + 1));
			}
			Hash hash;
			int hash0 = hash(kot(data)) % _tables.size();
			Node* newnode = new Node(data);
			newnode->_next = _tables[hash0];
			_tables[hash0] = newnode;
			++_n;
			return make_pair(Iterator(newnode, this), true);
		}

		Iterator Find(const K& key)
		{
			if (Empty())
				return End();

			Hash hash;
			KeyOfT kot;
			int hash0 = hash(key) % _tables.size();
			Node* cur = _tables[hash0];
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					return Iterator(cur,nullptr);
				}
				else
				{
					cur = cur->_next;
				}
			}
			return End();
		}

		Iterator Erase(const K& key)
		{
			if (Empty())
				return End();

			Hash hash;
			int hash0 = hash(key) % _tables.size();
			Node* cur = _tables[hash0];
			Node* prev = nullptr;
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					Iterator it(cur, this);
					it++;
					if (prev == nullptr)
					{
						_tables[hash0] = nullptr;
					}
					else
					{
						prev->_next = cur->_next;
					}
					delete cur;
					_n--;
					return it;
				}
				else
				{
					prev = cur;
					cur = cur->_next;
				}
			}
			return End();
		}
		size_t Size() const
		{
			return _n;
		}
		bool Empty() const
		{
			return _n == 0;
		}
	private:
		void Rehash(size_t newsize)
		{
			vector<Node*> newtables(newsize,nullptr);
			Hash hash;
			KeyOfT kot;
			for (auto& data : _tables)
			{
				Node* cur = data;
				while (cur)
				{
					Node* next = cur->_next;
					int hash0 = hash(kot(cur->_data)) % newsize;
					cur->_next = newtables[hash0];
					newtables[hash0] = cur;
					cur = next;
				}
				//这一句要写
				data = nullptr;
			}
			_tables.swap(newtables);
		}
		vector<HashNode<T>*> _tables;
		size_t _n;
	};
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值