【C++数据结构】哈希表HashMap与HashSet

目录

1. 前言 

2. 哈希表原理

3. 源码实现

4. 测试代码

5. 结尾


1. 前言 

        当前的存储结构本质上只有两种:数组、链表。数组支持随机访问,访问速度极快,哈希表就是利用这一点。

2. 哈希表原理

        ①哈希表的底层是数组,数组是通过下标索引访问的,那哈希表就要生成一个索引,为每一个元素分配唯一的索引,而生成这个索引的工具就叫做“哈希函数”,每一个存放数据的位置叫做“桶”。

        ②数组中的每一个元素以键值对key-value形式存在,索引就是通过用哈希函数将key转化为索引。至于怎么转化,这里举一个例子,假设数组容量为16,这里有一个key值为100的元素,那么哈希函数可以直接用 key % 16即100 % 16 = 4来计算,得到的结果4就是这个索引。当插入一个新的元素时,如果其索引位置上已有元素,那么就引入一个新的问题,哈希冲突

        ③哈希冲突的解决办法,这里只列举我代码实现的方法,也是教科书上的办法:当哈希冲突时,后来元素的索引需要一直增加1,即一直往后移动,直到找到空的位置为止。当插入一个新的元素后,如果容量已满,需要即时扩充容量,否则在下一次哈希冲突寻找空位置时会造成死循环。

3. 源码实现

①为了增加遍历哈希容器元素的方便性,我这里为每一个元素增加双向链表作为存储容器,遍历时就遍历这双向链表。

②代码已与C++11中的std::unordered_map和std::unordered_set作一定的兼容。

③代码支持C++03标准,可不必使用C++11以上版本,代码已在VS2005和GCC 4.1中编译通过。

 

头文件:HashTable.h

#ifndef HASH_TABLE_H
#define HASH_TABLE_H

#include <utility>
#include <cmath>
#include <string>

#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
#elif defined(Clang)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshift-count-overflow"
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4293)
#endif

#if __cplusplus >= 201703L
#define null nullptr
#define CONSTEXPR constexpr
#define CXX14_CONSTEXPR constexpr
#define CXX17_CONSTEXPR constexpr
#elif __cplusplus >= 201402L
#define null nullptr
#define CONSTEXPR constexpr
#define CXX14_CONSTEXPR constexpr
#define CXX17_CONSTEXPR
#elif __cplusplus >= 201103L
#define null nullptr
#define CONSTEXPR constexpr
#define CXX14_CONSTEXPR
#define CXX17_CONSTEXPR
#else
#define null 0
#define CONSTEXPR
#define CXX14_CONSTEXPR
#define CXX17_CONSTEXPR
#endif

typedef unsigned long HashType;

template<unsigned long _ByteCount>
HashType _Hash(const void *__ptr, unsigned long __len, unsigned long __seed);

template<>
HashType _Hash<32>(const void *__ptr, unsigned long __len, unsigned long __seed)
{
	const unsigned int __m = 0x5bd1e995;
	const int __r = 24;
	HashType __h = __seed ^ __len;
	const unsigned char *__data = static_cast<const unsigned char *>(__ptr);
	while(__len >= 4)
	{
		unsigned int __k = *reinterpret_cast<const unsigned int *>(__data);
		__k *= __m;
		__k ^= __k >> __r;
		__k *= __m;
		__h *= __m;
		__h ^= __k;
		__data += 4;
		__len -= 4;
	}
	switch(__len)
	{
	case 3: 
		__h ^= __data[2] << 16;
	case 2: 
		__h ^= __data[1] << 8;
	case 1: 
		__h ^= __data[0];
		__h *= __m;
	};
	__h ^= __h >> 13;
	__h *= __m;
	__h ^= __h >> 15;
	return __h;
}

template<>
HashType _Hash<64>(const void *__ptr, unsigned long __len, unsigned long __seed)
{
	const unsigned int __m = 0x5bd1e995;
	const int __r = 24;

	unsigned int __h1 = __seed ^ __len;
	unsigned int __h2 = 0;

	const unsigned int * __data = static_cast<const unsigned int *>(__ptr);

	while(__len >= 8)
	{
		unsigned int __k1 = *__data++;
		__k1 *= __m; 
		__k1 ^= __k1 >> __r; 
		__k1 *= __m;
		__h1 *= __m; 
		__h1 ^= __k1;
		__len -= 4;

		unsigned int __k2 = *__data++;
		__k2 *= __m; 
		__k2 ^= __k2 >> __r; 
		__k2 *= __m;
		__h2 *= __m; 
		__h2 ^= __k2;
		__len -= 4;
	}

	if(__len >= 4)
	{
		unsigned int __k1 = *__data++;
		__k1 *= __m; 
		__k1 ^= __k1 >> __r; 
		__k1 *= __m;
		__h1 *= __m; 
		__h1 ^= __k1;
		__len -= 4;
	}

	switch(__len)
	{
	case 3: 
		__h2 ^= (reinterpret_cast<const unsigned char*>(__data))[2] << 16;
	case 2: 
		__h2 ^= (reinterpret_cast<const unsigned char*>(__data))[1] << 8;
	case 1: 
		__h2 ^= (reinterpret_cast<const unsigned char*>(__data))[0];
		__h2 *= __m;
	};

	__h1 ^= __h2 >> 18; 
	__h1 *= __m;
	__h2 ^= __h1 >> 22;
	__h2 *= __m;
	__h1 ^= __h2 >> 17; 
	__h1 *= __m;
	__h2 ^= __h1 >> 19; 
	__h2 *= __m;

	HashType __h = __h1;

	__h = (__h << 32) | __h2;

	return __h;
}

template<unsigned long _ByteCount>
HashType _Hash(const void *__ptr, unsigned long __len);

template<>
HashType _Hash<32>(const void *__ptr, unsigned long __len)
{ return _Hash<32>(__ptr, __len, 97); }

template<>
HashType _Hash<64>(const void *__ptr, unsigned long __len)
{ return _Hash<64>(__ptr, __len, 0xEE6B27EB); }

template<typename _Tp>
struct Hash
{
	HashType operator()(const _Tp &_h) const
	{ return _h.Hash(); }
};

#define HASH_SPECIALIZED(type)                \
template<>                                    \
struct Hash<type>                             \
{                                             \
	HashType operator()(const type &c) const  \
	{ return static_cast<HashType>(c); }      \
};

HASH_SPECIALIZED(char)
HASH_SPECIALIZED(unsigned char)
HASH_SPECIALIZED(short)
HASH_SPECIALIZED(unsigned short)
HASH_SPECIALIZED(int)
HASH_SPECIALIZED(unsigned int)
HASH_SPECIALIZED(long)
HASH_SPECIALIZED(unsigned long)
HASH_SPECIALIZED(long long)
HASH_SPECIALIZED(unsigned long long)

template<>
struct Hash<std::string>
{
	HashType operator()(const std::string &_s) const 
	{ return _Hash<sizeof(HashType)>(_s.c_str(), _s.size()); }
};

template<typename _Tp>
struct Hash<_Tp *>
{
	HashType operator()(const _Tp *_h) const
	{ return reinterpret_cast<HashType>(_h); }
};

template<typename _Tp>
struct Equal
{
	bool operator()(const _Tp &_1, const _Tp &_2) const 
	{ return _1 == _2; }
};

template<typename _Key, 
		 typename _Value,
		 typename _Hash = Hash<_Key>,
		 typename _EqualTo = Equal<_Key>
		>
class HashTable
{
private:
	struct NodeType
	{
		NodeType(const _Key &k, const _Value &v)
			: key(k), value(v), next(null), prev(null)
		{ }
#if __plusplus >= 201103L
		NodeType(const _Key &k, _Value &&v)
			: key(k), value(std::move(v)), next(null), prev(null)
		{ }
#endif
		const _Key key;
		_Value value;
		NodeType *next;
		NodeType *prev;
	};

public:
	class const_iterator;

	class iterator
	{
	private:
		friend class HashTable;
		friend class const_iterator;

		NodeType *_M_data;

	public:
		iterator(NodeType *__v = null) : _M_data(__v) { }

		iterator operator++() 
		{ return iterator(_M_data = _M_data->next); }

		iterator operator++(int) 
		{ 
			iterator __ret(_M_data);
			_M_data = _M_data->next;
			return __ret; 
		}

		bool operator==(const iterator &__it) const 
		{ return _M_data == __it._M_data; }

		bool operator!=(const iterator &__it) const 
		{ return _M_data != __it._M_data; }

		_Value& operator*()
		{ return _M_data->value; }

		_Value* operator->()
		{ return &_M_data->value; }
	};

	class const_iterator
	{
	private:
		friend class HashTable;

		const NodeType *_M_data;

	public:
		const_iterator(const NodeType *__v = null) : _M_data(__v) { }
		const_iterator(const iterator &__i) : _M_data(__i._M_data) { }

		const_iterator operator++() 
		{ return const_iterator(_M_data = _M_data->next); }

		const_iterator operator++(int) 
		{ 
			const_iterator __ret(_M_data);
			_M_data = _M_data->next;
			return __ret; 
		}

		bool operator==(const const_iterator &__it) const 
		{ return _M_data == __it._M_data; }

		bool operator!=(const const_iterator &__it) const 
		{ return _M_data != __it._M_data; }

		const _Value& operator*()
		{ return _M_data->value; }

		const _Value* operator->()
		{ return &_M_data->value; }
	};

public:
	typedef unsigned long size_type;

public:
	HashTable()
		: _M_capacity(0), _M_count(0), _M_head(null), _M_tail(null), _M_data(null)
	{ _M_rehash(1, 0); }

	HashTable(size_type __bkts)
		: _M_capacity(0), _M_count(0), _M_head(null), _M_tail(null), _M_data(null)
	{ _M_rehash(__bkts, 0); }

	HashTable(const HashTable &__ht)
		: _M_capacity(0), _M_count(0), _M_head(null), _M_tail(null), _M_data(null)
	{ this->operator=(__ht); }

#if __cplusplus >= 201103L
	HashTable(HashTable &&__ht)
		: _M_capacity(0), _M_count(0), _M_head(null), _M_tail(null), _M_data(null)
	{ swap(__ht); }
#endif 

	~HashTable() 
	{ 
		clear(); 
		delete[] _M_data;
	}

	void clear()
	{
		if(_M_count == 0)
		{
			return;
		}
		for(size_type __i = 0; __i < _M_capacity; ++__i)
		{
			if(_M_data[__i])
			{
				delete _M_data[__i];
				_M_data[__i] = null;
			}
		}
		_M_count = 0;
		_M_head = _M_tail = null;
	}

	bool empty() const 
	{ return size() == 0; }

	size_type size() const 
	{ return _M_count; }

	size_type max_size() const 
	{ return _M_capacity; }

	size_type bucket_count() const 
	{ return max_size(); }

	size_type bucket_size(size_type) const 
	{ return 1; } 

	iterator begin()
	{ return iterator(_M_head); }

	const_iterator begin() const 
	{ return const_iterator(_M_head); }

	const_iterator cbegin() const 
	{ return begin(); }

	iterator end()
	{ return iterator(null); }

	const_iterator end() const 
	{ return const_iterator(null); }

	const_iterator cend() const 
	{ return const_iterator(null); }

	std::pair<iterator, bool> insert(const _Key &__k, const _Value &__v)
	{ return _M_insert(__k, __v); }

#if __cplusplus >= 201103L
	std::pair<iterator, bool> insert(const _Key &__k, _Value &&__v)
	{ return _M_insert(__k, std::move(__v)); }
#endif 

	const_iterator find(const _Key &__k) const 
	{ return _M_find_node(__k); }

	iterator find(const _Key &__k)
	{ return iterator(const_cast<NodeType *>(_M_find_node(__k)._M_data)); }

	void rehash(size_type __s)
	{ _M_rehash(__s, 0); }

	_Value& at(const _Key &__k, const _Value &__v)
	{ return _M_find_and_insert(__k, __v)._M_data->value; }

#if __cplusplus >= 201103L
	_Value& at(const _Key &__k, _Value &&__v)
	{ return _M_find_and_insert(__k, std::move(__v))._M_data->value; }
#endif 

	void erase(const _Key &__k)
	{ 
		const_iterator __beg = _M_find_node(__k);
		const_iterator __end = __beg;
		_M_erase(__beg, ++__end); 
	}

	void erase(const_iterator __beg, const_iterator __end)
	{ _M_erase(__beg, __end); }

	void swap(HashTable &__ht)
	{
		std::swap<size_type>(_M_capacity, __ht._M_capacity);
		std::swap<size_type>(_M_count, __ht._M_count);
		std::swap<NodeType *>(_M_head, __ht._M_head);
		std::swap<NodeType *>(_M_tail, __ht._M_tail);
		std::swap<NodeType **>(_M_data, __ht._M_data);
	}

	HashTable& operator=(const HashTable &__ht)
	{
		clear();
		rehash(__ht._M_capacity);
		for(size_type __i = 0; __i < __ht._M_capacity; ++__i)
		{
			NodeType *__node = __ht._M_data[__i];
			if(__node)
			{
				_M_insert(_M_data[__i] = new NodeType(__node->key, __node->value));
			}
		}
		return *this;
	}

private:
	std::pair<iterator, bool> _M_insert(const _Key &__k, const _Value &__v)
	{
		if(_M_capacity - _M_count <= 1)
		{
			_M_rehash(_M_capacity * 2);
		}

		_Hash __hash;
		HashType __code = __hash(__k);
		_EqualTo __e;
		size_type __index = _S_bucket_index(__code, _M_capacity);
		NodeType *__node = null;

		while(_M_data[__index])
		{
			__node = _M_data[__index];
			if(__e(__node->key, __k))
			{
				return std::pair<iterator, bool>(iterator(__node), false);
			}
			__index = _M_inc(__index, _M_capacity);
		}

		__node = new NodeType(__k, __v);
		_M_data[__index] = __node;
		return std::pair<iterator, bool>(_M_insert(__node), true);
	}

#if __cplusplus >= 201103L
	std::pair<iterator, bool> _M_insert(const _Key &__k, _Value &&__v)
	{
		if(_M_capacity - _M_count <= 1)
		{
			_M_rehash(_M_capacity * 2);
		}

		_Hash __hash;
		HashType __code = __hash(__k);
		_EqualTo __e;
		size_type __index = _S_bucket_index(__code, _M_capacity);
		NodeType *__node = null;

		while(_M_data[__index])
		{
			__node = _M_data[__index];
			if(__e(__node->key, __k))
			{
				return std::pair<iterator, bool>(iterator(__node), false);
			}
			__index = _M_inc(__index, _M_capacity);
		}

		__node = new NodeType(__k, std::move(__v));
		_M_data[__index] = __node;
		return std::pair<iterator, bool>(_M_insert(__node), true);
	}
#endif

	iterator _M_find_and_insert(const _Key &__k, const _Value &__v)
	{
		const_iterator __f = _M_find_node(__k);
		return __f == cend()
			? _M_insert(__k, __v).first
			: iterator(const_cast<NodeType *>(__f._M_data));
	}

#if __cplusplus >= 201103L
	iterator _M_find_and_insert(const _Key &__k, _Value &&__v)
	{
		const_iterator __f = _M_find_node(__k);
		return __f == cend()
			? _M_insert(__k, std::move(__v)).first
			: iterator(const_cast<NodeType *>(__f._M_data));
	}
#endif

	static CXX14_CONSTEXPR size_type _M_inc(size_type __s, size_type __max)
	{ return ++__s >= __max ? 0 : __s; }

	static CXX14_CONSTEXPR size_type _S_bucket_index(size_type __code, size_type __bkt_count)
	{ return __code % __bkt_count; }

	static CXX14_CONSTEXPR size_type _S_clp2(size_type __n)
	{
		size_type __x = __n;
		__x = __x - 1;
		__x = __x | (__x >> 1);
		__x = __x | (__x >> 2);
		__x = __x | (__x >> 4);
		__x = __x | (__x >> 8);
		__x = __x | (__x >> 16);
		if CXX17_CONSTEXPR (sizeof(size_type) >= 8)
		{
			__x = __x | (__x >> 32);
		}
		return __x + 1;
	}

	static CXX14_CONSTEXPR bool _S_is_prime(size_type __n)
	{
		if (__n <= 3) 
		{
			return __n > 1;
		}
		if (__n % 6 != 1 && __n % 6 != 5) 
		{
			return false;
		}

		size_type __s = static_cast<size_type>(::sqrt(double(__n)));
		for (size_type __i = 5; __i <= __s; __i += 6) 
		{
			if (__n % __i == 0 || __n % (__i + 2) == 0) 
			{
				return false;
			}
		}
		return true;
	}

	static CXX14_CONSTEXPR size_type _S_next_bucket(size_type __n)
	{
		if(__n <= 1)
		{
			return 1;
		}
		if(__n == 2 || __n == 3)
		{
			return __n;
		}
		__n = _S_clp2(__n) - 1;
		while(!_S_is_prime(__n))
		{ __n -= 2; }
		return __n;
	}

	void _M_rehash(size_type __bkts, size_type __its = 1)
	{
		__bkts = _S_next_bucket(__bkts);
		while(_M_count + __its > __bkts)
		{
			__bkts = _S_next_bucket(__bkts << 1);
		}

		NodeType **__tmp = new NodeType*[__bkts];
		for(size_type i = 0; i < __bkts; ++i)
		{
			__tmp[i] = null;
		}

		_Hash __hash;
		for(iterator __it = begin(); __it != end(); ++__it)
		{
			NodeType *__node = __it._M_data;
			size_type __index = _S_bucket_index(__hash(__node->key), __bkts);
			while(__tmp[__index])
			{
				__index = _M_inc(__index, __bkts);
			}
			__tmp[__index] = __node;
		}

		delete[] _M_data;
		_M_data = __tmp;
		_M_capacity = __bkts;
	}

	const_iterator _M_find_node(const _Key &key) const
	{
		_Hash __hash;
		HashType __code = __hash(key);
		_EqualTo __e;
		NodeType *__node = null;
		size_type __index = _S_bucket_index(__code, _M_capacity);

		while(_M_data[__index])
		{
			__node = _M_data[__index];
			if(__e(key, __node->key))
			{
				return const_iterator(__node);
			}
			__index = _M_inc(__index, _M_capacity);
		}
		return const_iterator(null);
	}

	iterator _M_insert(NodeType *__n)
	{
		if(!_M_head)
		{
			_M_head = _M_tail = __n;
		}
		else 
		{
			_M_tail->next = __n;
			__n->prev = _M_tail;
			_M_tail = __n;
		}
		++_M_count;
		return iterator(__n);
	}

	void _M_erase(const_iterator __beg, const_iterator __end)
	{
		while(__beg != __end)
		{
			_M_erase((__beg++)._M_data);
		}
	}

	void _M_erase(const NodeType *__node)
	{
		if(!__node)
		{
			return;
		}

		_Hash __hash;
		HashType __code = __hash(__node->key);
		_EqualTo __e;
		size_type __index = _S_bucket_index(__code, _M_capacity);

		while(_M_data[__index])
		{
			const NodeType *__n = _M_data[__index];
			if(__e(__n->key, __node->key))
			{
				_M_data[__index] = null;
				break;
			}
			__index = _M_inc(__index, _M_capacity);
		}

		NodeType *__p = __node->prev;
		NodeType *__n = __node->next;
		if(__node == _M_head)
		{
			_M_head = __n;
			_M_head->prev = null;
		}
		else if(__node == _M_tail)
		{
			_M_tail = __p;
			_M_tail->next = null;
		}
		else 
		{
			__p->next = __n;
			__n->prev = __p;
		}
		delete __node;
		--_M_count;
	}

private:
	size_type _M_capacity;
	size_type _M_count;
	NodeType *_M_head;
	NodeType *_M_tail;
	NodeType **_M_data;
};


#ifdef __GNUC__
#pragma GCC diagnostic pop
#elif defined(Clang)
#pragma clang diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif

#endif // HASH_TABLE_H

头文件:HashMap.h

#ifndef HASH_MAP_H
#define HASH_MAP_H

#include "HashTable.h"

template<typename _Key, 
		 typename _Value,
		 typename _Hash = Hash<_Key>,
		 typename _EqualTo = Equal<_Key>
		>
class HashMap
{ 
private:
	typedef HashTable<_Key, std::pair<_Key, _Value>, _Hash, _EqualTo> _HashTable;

public:
	typedef typename _HashTable::iterator iterator;
	typedef typename _HashTable::const_iterator const_iterator;

public:
	typedef _Key                             key_type;
	typedef _Value                           mapped_type;
	typedef std::pair<key_type, mapped_type> value_type;
	typedef typename _HashTable::size_type   size_type;

public:	
	HashMap() {}
	HashMap(const HashMap &__m)
		: _M_impl(__m._M_impl) { }

#if __cplusplus >= 201103L
	HashMap(HashMap &&__m)
		: _M_impl(std::move(__m._M_impl)) { }
#endif

	_Value& at(const _Key &__k)
	{ return _M_impl.at(__k, value_type(__k, mapped_type())).second; }

	_Value& operator[](const _Key &__k)
	{ return _M_impl.at(__k, value_type(__k, mapped_type())).second; }

	std::pair<iterator, bool> insert(const _Key &__k, const _Value &__v)
	{ return _M_impl.insert(__k, value_type(__k, __v)); }

	std::pair<iterator, bool> insert(const std::pair<_Key, _Value> &__p)
	{ return _M_impl.insert(__p.first, __p); }

#if __cplusplus >= 201103L
	std::pair<iterator, bool> insert(std::pair<_Key, _Value> &&__p)
	{ return _M_impl.insert(__p.first, std::move(__p)); }
#endif

	void erase(const_iterator __i)
	{ 
		const_iterator __e = __i;
		_M_impl.erase(__i, ++__e); 
	}

	void erase(iterator __i)
	{
		const_iterator __e = __i;
		_M_impl.erase(__i, ++__e); 
	}

	void erase(const_iterator __b, const_iterator __e)
	{ _M_impl.erase(__b, __e); }

	size_type erase(const _Key &__k)
	{ 
		iterator __f = find(__k);
		if(__f == end())
		{ return 0; }
		_M_impl.erase(__f); 
		return 1;
	}

	size_type max_size() const 
	{ return _M_impl.max_size(); }

	void rehash(size_type __s)
	{ _M_impl.rehash(__s); }

	size_type size() const 
	{ return _M_impl.size(); }

	size_type count(const _Key &__k) const 
	{ return static_cast<size_type>(contains(__k)); }

	size_type bucket_count() const 
	{ return _M_impl.bucket_count(); }

	void swap(HashMap &__m)
	{ _M_impl.swap(__m._M_impl); }

	bool empty() const 
	{ return _M_impl.empty(); }

	iterator find(const _Key &__k)
	{ return _M_impl.find(__k); }

	const_iterator find(const _Key &__k) const 
	{ return _M_impl.find(__k); }

	bool contains(const _Key &__k) const
	{ return find(__k) != end(); }

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

	const_iterator begin() const 
	{ return _M_impl.begin(); }

	const_iterator cbegin() const 
	{ return _M_impl.cbegin(); }

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

	const_iterator end() const 
	{ return _M_impl.end(); }

	const_iterator cend() const 
	{ return _M_impl.cend(); }

	void clear() 
	{ _M_impl.clear(); }

private:
	_HashTable _M_impl;
};

#endif // HASH_MAP_H

头文件:HashSet.h

#ifndef HASH_SET_H
#define HASH_SET_H
 
#include "HashTable.h"
 
template<typename _Key, 
         typename _Hash = Hash<_Key>,
         typename _EqualTo = Equal<_Key>
		 >
class HashSet
{ 
private:
	typedef HashTable<_Key, _Key, _Hash, _EqualTo> _HashTable;
 
public:
	typedef typename _HashTable::const_iterator iterator;
	typedef typename _HashTable::const_iterator const_iterator;
 
public:
	typedef _Key                   key_type;
	typedef _Key                   value_type;
	typedef typename _HashTable::size_type  size_type;
 
public:	
    HashSet() {}
    HashSet(const HashSet &__s)
     : _M_impl(__s._M_impl) { }

#if __cplusplus >= 201103L
    HashSet(HashSet &&__s)
     : _M_impl(std::move(__s._M_impl)) { }
#endif

	std::pair<iterator, bool> insert(const _Key &__k)
	{ return _M_impl.insert(__k, __k); }
 
	void erase(const_iterator __i)
	{ 
		const_iterator __e = __i;
		_M_impl.erase(__i, ++__e); 
	}
 
	void erase(const_iterator __b, const_iterator __e)
	{ _M_impl.erase(__b, __e); }
 
	size_type erase(const _Key &__k)
	{ 
		iterator __f = find(__k);
		if(__f == end())
		{ return 0; }
		_M_impl.erase(__f); 
		return 1;
	}
 
	size_type max_size() const 
	{ return _M_impl.max_size(); }
 
	void rehash(size_type __s)
	{ _M_impl.rehash(__s); }
 
	size_type size() const 
	{ return _M_impl.size(); }
 
	size_type count(const _Key &__k) const 
	{ return static_cast<size_type>(contains(__k)); }
 
	size_type bucket_count() const 
	{ return _M_impl.bucket_count(); }
 
	void swap(HashSet &__m)
	{ _M_impl.swap(__m._M_impl); }
 
	bool empty() const 
	{ return _M_impl.empty(); }
 
	iterator find(const _Key &__k)
	{ return _M_impl.find(__k); }
 
	const_iterator find(const _Key &__k) const 
	{ return _M_impl.find(__k); }
 
	bool contains(const _Key &__k) const
	{ return find(__k) != end(); }
 
    iterator begin()
    { return _M_impl.begin(); }
 
    const_iterator begin() const 
    { return _M_impl.begin(); }
 
    const_iterator cbegin() const 
    { return _M_impl.cbegin(); }
 
    iterator end()
    { return _M_impl.end(); }
 
    const_iterator end() const 
    { return _M_impl.end(); }
 
    const_iterator cend() const 
    { return _M_impl.cend(); }
 
	void clear() 
	{ _M_impl.clear(); }
 
private:
    _HashTable _M_impl;
};
 
 
#endif // HASH_SET_H

4. 测试代码

源码:

#include <iostream>
#include "HashMap.h"
#include "HashSet.h"

struct A
{
	int v;
	A(int vv = 0) : v(vv) 
	{ }

	friend std::ostream& operator<<(std::ostream &os, const A &a)
	{ 
		os << a.v;
		return os;
	}

	bool operator==(const A &a) const 
	{ return v == a.v; }
};

struct A_Hash
{
	HashType operator()(const A &a) const 
	{ return static_cast<HashType>(a.v); }
};

typedef HashMap<int, A, A_Hash> TestHashMap;
typedef HashSet<A, A_Hash> TestHashSet;

static void print(const TestHashMap &a)
{
	for(TestHashMap::const_iterator it = a.begin(); it != a.end(); ++it)
	{
		std::cout << it->second.v << ' ';
	}
	std::cout << std::endl;
}

static void print(const TestHashSet &a)
{
	for(TestHashSet::const_iterator it = a.begin(); it != a.end(); ++it)
	{
		std::cout << *it << ' ';
	}
	std::cout << std::endl;
}

static void print_insert(TestHashMap &a, int k, const A &v)
{
	static int index = 0;

	std::cout << "---------------insert node: " << ++index << "-------------------" << std::endl;
	std::cout << "node: " << k << "<--->" << v << std::endl;
	a.insert(std::make_pair(k, v));
	std::cout << "bkt size : " << a.bucket_count() << std::endl;
	print(a);
}

static void test_hashmap()
{
	std::cout << "******************** test_hashmap ***********************" << std::endl;
	TestHashMap a;
	print_insert(a, 1, A(10));
	print_insert(a, 3, A(30));
	print_insert(a, 2, A(20));
	print_insert(a, 7, A(70));
	print_insert(a, 0, A(0));
	print_insert(a, 4, A(4));
	print_insert(a, 8, A(80));
	a[20] = A(200);

	std::cout << "------------------find node----------------" << std::endl;
	TestHashMap::iterator found = a.find(0);
	if(found != a.end())
	{
		std::cout << "0 is exists! its value: " << found->second << std::endl;
	}

	found = a.find(100);
	if(found == a.end())
	{
		std::cout << "100 is not exists!!" << std::endl;
	}

	std::cout << "--------------remove node: 2--20" << std::endl;
	a.erase(a.find(2));
	print(a);
}

static void test_hashset()
{
	std::cout << "******************** test_hashset ***********************" << std::endl;
	TestHashSet a;
	a.insert(A(10));
	a.insert(A(-1));
	a.insert(A(1));
	a.insert(A(8));
	a.insert(A(100));

	std::cout << "node list: ";
	print(a);
	std::cout << "node 10 is exists? " << std::boolalpha << a.contains(10) << std::endl;

	std::cout << "---------- remove node : -1 -----------------" << std::endl; 
	TestHashSet::const_iterator found = a.find(A(-1));
	if(found != a.end())
	{
		a.erase(found);
	}
	std::cout << "node list: ";
	print(a);
}

int main()
{
    test_hashmap();
    test_hashset();
    return 0;
}

输出结果:

5. 结尾

如有问题,欢迎指出!

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值