C++ 高级编程 编写一个 STL 容器:基本 hashmap

参考 C++ 高级编程,实现一个 STL 容器:基本 hashmap

hashmap.h

#include <stdexcept>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <iterator>

using namespace std;

template<typename T>
class DefaultHash
{
	public:
		DefaultHash(int numBuckets = 101) throw(std::invalid_argument);
		int hash(const T& key) const;
		int numBuckets() const 
		{
			return mNumBuckets;
		}

	private:
		int mNumBuckets;
};

	template<typename T>
DefaultHash<T>::DefaultHash(int numBuckets) throw(std::invalid_argument)
{
	if (numBuckets <= 0)
	{
		throw std::invalid_argument("numBuckets must be > 0");
	}

	mNumBuckets = numBuckets;
}

template<typename T>
int DefaultHash<T>::hash(const T& key) const 
{
	int bytes = sizeof(key);
	unsigned long ret = 0;
	for (int i = 0; i < bytes; ++i)
	{
		ret += *((char*)&key + i);
	}
	return ret % mNumBuckets;
}

template<>
class DefaultHash<string>
{
	public:
		DefaultHash(int numBuckets = 101) throw(std::invalid_argument);
		int hash(const string& key) const;
		int numBuckets() const 
		{
			return mNumBuckets;
		}

	private:
		int mNumBuckets;
};

DefaultHash<string>::DefaultHash(int numBuckets) throw(std::invalid_argument)
{
	if (numBuckets <= 0)
	{
		throw std::invalid_argument("numBuckets must be > 0");
	}

	mNumBuckets = numBuckets;
}

int DefaultHash<string>::hash(const string& key) const 
{
	int sum = 0;
	for (size_t i = 0; i < key.size(); ++i)
	{
		sum += key[i];
	}
	return sum % mNumBuckets;
}

template<typename Key, typename T, typename Compare, typename Hash>
class HashIterator;

template<typename Key, typename T, typename Compare = std::equal_to<Key>, typename Hash = DefaultHash<Key> >
class hashmap
{
	public:
		typedef Key key_type;
		typedef T mapped_type;
		typedef pair<const Key, T> value_type;
		typedef pair<const Key, T>& reference;
		typedef const pair<const Key, T>& const_reference;
		typedef size_t size_type;
		typedef ptrdiff_t difference_type;
		typedef HashIterator<Key, T, Compare, Hash> iterator;
		typedef HashIterator<Key, T, Compare, Hash> const_iterator;
		typedef Compare key_compare;

		class value_compare
			: public std::binary_function<value_type, value_type, bool>
		{
			public:
				bool operator()(const value_type& x, const value_type& y) const 
				{
					return comp(x.first, y.first);
				}

				friend class hashmap<Key, T, Compare, Hash>;

			private:
				value_compare(Compare c)
					: comp(c)
				{

				}

				Compare comp;
		};

		friend class HashIterator<Key, T, Compare, Hash>;

		explicit hashmap(const Compare& comp = Compare(), const Hash& hash = Hash()) throw(std::invalid_argument);

		template<typename InputIterator>
			hashmap(InputIterator first, InputIterator last, const Compare& comp = Compare(), const Hash& = Hash()) throw(std::invalid_argument);

		~hashmap();
		hashmap(const hashmap<Key, T, Compare, Hash>& src);
		hashmap<Key, T, Compare, Hash>& operator=(const hashmap<Key, T, Compare, Hash>& rhs);

		template<typename InputIterator>
			void insert(InputIterator first, InputIterator last);

		pair<iterator, bool> insert(const value_type& x);
		iterator insert(iterator position, const value_type& x);

		void erase(iterator position);
		size_type erase(const key_type& x);
		void erase(iterator first, iterator last);

		void clear();
		key_compare key_comp() const;
		value_compare value_comp() const;

		iterator find(const key_type& x);
		const_iterator find(const key_type& x) const;

		T& operator[](const key_type& x);

		bool empty() const;
		size_type size() const;
		size_type max_size() const;
		size_type count(const key_type& x) const;

		void swap(hashmap<Key, T, Compare, Hash>& hashIn);

		iterator begin();
		iterator end();
		const_iterator begin() const;
		const_iterator end() const;

	private:
		typedef list<value_type> ListType;

		typename ListType::iterator findElement(const key_type& x, int& bucket) const;

		vector<ListType>* mElems;
		int mSize;
		Compare mComp;
		Hash mHash;
};

	template<typename Key, typename T, typename Compare, typename Hash>
hashmap<Key, T, Compare, Hash>::hashmap(const Compare& comp, const Hash& hash) throw(std::invalid_argument)
	: mSize(0), mComp(comp), mHash(hash)
{
	if (mHash.numBuckets() <= 0)
	{
		throw std::invalid_argument("number of buckets must be positive");
	}

	mElems = new vector<ListType>(mHash.numBuckets());
}

template<typename Key, typename T, typename Compare, typename Hash>
	template<typename InputIterator>
hashmap<Key, T, Compare, Hash>::hashmap(InputIterator first, InputIterator last, const Compare& comp, const Hash& hash) throw(std::invalid_argument)
	: mSize(0), mComp(comp), mHash(hash)
{
	if (mHash.numBuckets() <= 0)
	{
		throw std::invalid_argument("number of buckets must be positive");
	}

	mElems = new vector<ListType>(mHash.numBuckets());
	insert(first, last);
}

	template<typename Key, typename T, typename Compare, typename Hash>
hashmap<Key, T, Compare, Hash>::~hashmap()
{
	delete mElems;
}

	template<typename Key, typename T, typename Compare, typename Hash>
hashmap<Key, T, Compare, Hash>::hashmap(const hashmap<Key, T, Compare, Hash>& src)
	: mSize(src.mSize), mComp(src.mComp), mHash(src.mHash)
{
	mElems = new vector<ListType>(*(src.mElems));
}

	template<typename Key, typename T, typename Compare, typename Hash>
hashmap<Key, T, Compare, Hash>& hashmap<Key, T, Compare, Hash>::operator=(const hashmap<Key, T, Compare, Hash>& rhs)
{
	if (this != &rhs)
	{
		delete mElems;
		mSize = rhs.mSize;
		mComp = rhs.mComp;
		mHash = rhs.mHash;
		mElems = new vector<ListType>(*(rhs.mElems));
	}

	return *this;
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::ListType::iterator hashmap<Key, T, Compare, Hash>::findElement(const key_type& x, int& bucket) const 
{
	bucket = mHash.hash(x);
	for (typename ListType::iterator it = (*mElems)[bucket].begin(); it != (*mElems)[bucket].end(); ++it)
	{
		if (mComp(it->first, x))
		{
			return it;
		}
	}

	return (*mElems)[bucket].end();
}

	template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::iterator hashmap<Key, T, Compare, Hash>::find(const key_type& x)
{
	int bucket;
	typename ListType::iterator it = findElement(x, bucket);
	if (it == (*mElems)[bucket].end())
	{
		return end();
	}

	return HashIterator<Key, T, Compare, Hash>(bucket, it, this);
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::const_iterator hashmap<Key, T, Compare, Hash>::find(const key_type& x) const 
{
	int bucket;
	typename ListType::iterator it = findElement(x, bucket);
	if (it == (*mElems)[bucket].end())
	{
		return end();
	}

	return HashIterator<Key, T, Compare, Hash>(bucket, it, this);
}

	template<typename Key, typename T, typename Compare, typename Hash>
T& hashmap<Key, T, Compare, Hash>::operator[](const key_type& x)
{
	return (insert(make_pair(x, T())).first)->second;
}

	template<typename Key, typename T, typename Compare, typename Hash>
pair<typename hashmap<Key, T, Compare, Hash>::iterator, bool> hashmap<Key, T, Compare, Hash>::insert(const value_type& x)
{
	int bucket;
	typename ListType::iterator it = findElement(x.first, bucket);

	if (it != (*mElems)[bucket].end())
	{
		HashIterator<Key, T, Compare, Hash> newIt(bucket, it, this);
		pair<HashIterator<Key, T, Compare, Hash>, bool> p(newIt, false);
		return p;
	}
	else 
	{
		++mSize;
		typename ListType::iterator endIt = (*mElems)[bucket].insert((*mElems)[bucket].end(), x);
		pair<HashIterator<Key, T, Compare, Hash>, bool> p(HashIterator<Key, T, Compare, Hash>(bucket, endIt, this), true);
		return p;
	}
}

template<typename Key, typename T, typename Compare, typename Hash>
	template<typename InputIterator>
void hashmap<Key, T, Compare, Hash>::insert(InputIterator first, InputIterator last)
{
	insert_iterator<hashmap<Key, T, Compare, Hash> > inserter(*this, begin());
	copy(first, last, inserter);
}

	template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::iterator hashmap<Key, T, Compare, Hash>::insert(typename hashmap<Key, T, Compare, Hash>::iterator position, const value_type& x)
{
	(void)position;
	return insert(x).first;
}

	template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::size_type hashmap<Key, T, Compare, Hash>::erase(const key_type& x)
{
	int bucket;
	typename ListType::iterator it = findElement(x, bucket);
	if (it != (*mElems)[bucket].end())
	{
		(*mElems)[bucket].erase(it);
		--mSize;
		return 1;
	}

	return 0;
}

	template<typename Key, typename T, typename Compare, typename Hash>
void hashmap<Key, T, Compare, Hash>::erase(typename hashmap<Key, T, Compare, Hash>::iterator position)
{
	(*mElems)[position.getBucket()].erase(position.getIterator());
	--mSize;
}

	template<typename Key, typename T, typename Compare, typename Hash>
void hashmap<Key, T, Compare, Hash>::erase(typename hashmap<Key, T, Compare, Hash>::iterator first, typename hashmap<Key, T, Compare, Hash>::iterator last)
{
	typename hashmap<Key, T, Compare, Hash>::iterator cur, next;
	for (next = first; next != last; )
	{
		cur = next++;
		erase(cur);
	}
}

	template<typename Key, typename T, typename Compare, typename Hash>
void hashmap<Key, T, Compare, Hash>::clear()
{
	for_each(mElems->begin(), mElems->end(), mem_fun_ref(&ListType::clear));
	mSize = 0;
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::key_compare hashmap<Key, T, Compare, Hash>::key_comp() const 
{
	return mComp;
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::value_compare hashmap<Key, T, Compare, Hash>::value_comp() const 
{
	return value_compare(mComp);
}

template<typename Key, typename T, typename Compare, typename Hash>
bool hashmap<Key, T, Compare, Hash>::empty() const 
{
	return mSize == 0;
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::size_type hashmap<Key, T, Compare, Hash>::size() const 
{
	return mSize;
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::size_type hashmap<Key, T, Compare, Hash>::max_size() const 
{
	return (*mElems)[0].max_size();
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::size_type hashmap<Key, T, Compare, Hash>::count(const key_type& x) const 
{
	if (find(x) == end())
	{
		return 0;
	}
	else 
	{
		return 1;
	}
}

	template<typename Key, typename T, typename Compare, typename Hash>
void hashmap<Key, T, Compare, Hash>::swap(hashmap<Key, T, Compare, Hash>& hashIn)
{
	std::swap(*this, hashIn);
}

	template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::iterator hashmap<Key, T, Compare, Hash>::begin()
{
	if (mSize == 0)
	{
		return end();
	}

	for (size_t i = 0; i < mElems->size(); ++i)
	{
		if (!((*mElems)[i].empty()))
		{
			return HashIterator<Key, T, Compare, Hash>(i, (*mElems)[i].begin(), this);
		}
	}

	return end();
}

	template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::iterator hashmap<Key, T, Compare, Hash>::end()
{
	return HashIterator<Key, T, Compare, Hash>(mElems->size() - 1, (*mElems)[mElems->size() - 1].end(), this);
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::const_iterator hashmap<Key, T, Compare, Hash>::begin() const 
{
	if (mSize == 0)
	{
		return end();
	}

	for (size_t i = 0; i < mElems->size(); ++i)
	{
		if (!((*mElems)[i].empty()))
		{
			return HashIterator<Key, T, Compare, Hash>(i, (*mElems)[i].begin(), this);
		}
	}

	return end();
}

template<typename Key, typename T, typename Compare, typename Hash>
typename hashmap<Key, T, Compare, Hash>::const_iterator hashmap<Key, T, Compare, Hash>::end() const 
{
	return HashIterator<Key, T, Compare, Hash>(mElems->size() - 1, (*mElems)[mElems->size() - 1].end(), this);
}

template<typename Key, typename T, typename Compare, typename Hash>
class HashIterator : public std::iterator<std::bidirectional_iterator_tag, pair<const Key, T> >
{
	public:
		HashIterator();
		HashIterator(int bucket, typename list<pair<const Key, T> >::iterator listIt, const hashmap<Key, T, Compare, Hash>* inHashMap);

		pair<const Key, T>& operator*() const;
		pair<const Key, T>* operator->() const;

		HashIterator<Key, T, Compare, Hash>& operator++();
		const HashIterator<Key, T, Compare, Hash> operator++(int);

		HashIterator<Key, T, Compare, Hash>& operator--();
		const HashIterator<Key, T, Compare, Hash> operator--(int);

		bool operator==(const HashIterator& rhs) const;
		bool operator!=(const HashIterator& rhs) const;

		const HashIterator<Key, T, Compare, Hash>& operator+(int);
		const HashIterator<Key, T, Compare, Hash>& operator-(int);

		int getBucket() const 
		{
			return mBucket;
		}

		typename list<pair<const Key, T> >::iterator getIterator() const 
		{
			return mIt;
		}

	private:
		void increment();
		void decrement();

		int mBucket;
		typename list<pair<const Key, T> >::iterator mIt;
		const hashmap<Key, T, Compare, Hash>* mHashMap;
};

	template<typename Key, typename T, typename Compare, typename Hash>
HashIterator<Key, T, Compare, Hash>::HashIterator()
{
	mBucket = -1;
	mIt = typename list<pair<const Key, T> >::iterator();
	mHashMap = NULL;
}

	template<typename Key, typename T, typename Compare, typename Hash>
HashIterator<Key, T, Compare, Hash>::HashIterator(int bucket, typename list<pair<const Key, T> >::iterator listIt, const hashmap<Key, T, Compare, Hash>* inHashMap)
	: mBucket(bucket), mIt(listIt), mHashMap(inHashMap)
{

}

template<typename Key, typename T, typename Compare, typename Hash>
pair<const Key, T>& HashIterator<Key, T, Compare, Hash>::operator*() const 
{
	return *mIt;
}

template<typename Key, typename T, typename Compare, typename Hash>
pair<const Key, T>* HashIterator<Key, T, Compare, Hash>::operator->() const 
{
	return &(*mIt);
}

	template<typename Key, typename T, typename Compare, typename Hash>
HashIterator<Key, T, Compare, Hash>& HashIterator<Key, T, Compare, Hash>::operator++()
{
	increment();
	return *this;
}

	template<typename Key, typename T, typename Compare, typename Hash>
const HashIterator<Key, T, Compare, Hash> HashIterator<Key, T, Compare, Hash>::operator++(int)
{
	HashIterator<Key, T, Compare, Hash> oldIt = *this;
	increment();
	return oldIt;
}

	template<typename Key, typename T, typename Compare, typename Hash>
HashIterator<Key, T, Compare, Hash>& HashIterator<Key, T, Compare, Hash>::operator--()
{
	decrement();
	return *this;
}

	template<typename Key, typename T, typename Compare, typename Hash>
const HashIterator<Key, T, Compare, Hash> HashIterator<Key, T, Compare, Hash>::operator--(int)
{
	HashIterator<Key, T, Compare, Hash> newIt = *this;
	decrement();
	return newIt;
}

template<typename Key, typename T, typename Compare, typename Hash>
bool HashIterator<Key, T, Compare, Hash>::operator==(const HashIterator& rhs) const 
{
	return (mHashMap == rhs.mHashMap) && (mBucket == rhs.mBucket) && (mIt == rhs.mIt);
}

template<typename Key, typename T, typename Compare, typename Hash>
bool HashIterator<Key, T, Compare, Hash>::operator!=(const HashIterator& rhs) const 
{
	return !(operator==(rhs));
}

	template<typename Key, typename T, typename Compare, typename Hash>
const HashIterator<Key, T, Compare, Hash>& HashIterator<Key, T, Compare, Hash>::operator+(int step)
{
	for (int i = 0; i < step; ++i)
	{
		increment();
	}
	return *this;
}

	template<typename Key, typename T, typename Compare, typename Hash>
const HashIterator<Key, T, Compare, Hash>& HashIterator<Key, T, Compare, Hash>::operator-(int step)
{
	for (int i = 0; i < step; ++i)
	{
		decrement();
	}
	return *this;
}

	template<typename Key, typename T, typename Compare, typename Hash>
void HashIterator<Key, T, Compare, Hash>::increment()
{
	++mIt;
	if (mIt == (*(mHashMap->mElems))[mBucket].end())
	{
		for (size_t i = mBucket + 1; i < (*(mHashMap->mElems)).size(); ++i)
		{
			if (!((*(mHashMap->mElems))[i].empty()))
			{
				mIt = (*(mHashMap->mElems))[i].begin();
				mBucket = i;
				return;
			}
		}

		mBucket = (*(mHashMap->mElems)).size() - 1;
		mIt = (*(mHashMap->mElems))[mBucket].end();
	}
}

	template<typename Key, typename T, typename Compare, typename Hash>
void HashIterator<Key, T, Compare, Hash>::decrement()
{
	if (mIt == (*(mHashMap->mElems))[mBucket].begin())
	{
		for (int i = mBucket - 1; i >= 0; --i)
		{
			if (!((*(mHashMap->mElems))[i].empty()))
			{
				mIt = (*(mHashMap->mElems))[i].end();
				--mIt;
				mBucket = i;
				return;
			}
		}

		mIt = (*(mHashMap->mElems))[0].begin();
		--mIt;
		mBucket = 0;
	}
	else 
	{
		--mIt;
	}
}

test.cpp

#include "hashmap.h"
#include <iostream>
#include <map>

using namespace std;

void printHashMap(const hashmap<string, int>& myMap);

int main()
{
	DefaultHash<int> hash;
	cout << hash.hash(23) << endl;;

	DefaultHash<string> hash2;
	cout << hash2.hash("my hashmap") << endl;

	hashmap<int, int> hm;
	hm.insert(make_pair(4, 40));
	hm.insert(make_pair(5, 50));

	hashmap<int, int>::iterator x = hm.find(4);
	if (x != hm.end())
	{
		cout << "4 maps to " << x->second << endl;
	}
	else 
	{
		cout << "can not find 4 in map" << endl;
	}

	cout << hm.size() << " " << hm.max_size() << endl;

	hm.erase(4);

	x = hm.find(4);
	if (x != hm.end())
	{
		cout << "4 maps to " << x->second << endl;
	}
	else 
	{
		cout << "can not find 4 in map" << endl;
	}

	cout << hm.size() << " " << hm.max_size() << endl;

	hm[4] = 35;
	cout << hm[4] << endl;

	cout << hm.size() << " " << hm.max_size() << endl;

	list<pair<int, int> > l;
	vector<list<pair<int, int> > > v;
	cout << l.max_size() << " " << v.max_size() << endl;

	hashmap<string, int> myHash;
	cout << boolalpha << myHash.empty() << endl;
	myHash.insert(make_pair("KeyOne", 100));
	myHash.insert(make_pair("KeyTwo", 200));
	myHash.insert(make_pair("KeyThree", 300));
	myHash.insert(myHash.begin(), make_pair("KeyFour", 400));
	myHash.insert(myHash.end(), make_pair("KeyFive", 500));
	cout << boolalpha << myHash.empty() << endl;
	cout << myHash.count("KeyFive") << " " << myHash.count("KeySix") << endl;
	printHashMap(myHash);

	map<string, int> myMap;
	myMap.insert(make_pair("KeyMap", 1000));
	myMap.insert(make_pair("KeyMap2", 2000));
	myMap.insert(make_pair("KeyMap3", 3000));

	hashmap<string, int> myHash2(myMap.begin(), myMap.end());
	printHashMap(myHash2);

	myHash2.swap(myHash);
	printHashMap(myHash);
	printHashMap(myHash2);
	myHash2.swap(myHash);

	myHash.insert(myMap.begin(), myMap.end());
	printHashMap(myHash);

	hashmap<string, int> myHash3(myHash);
	printHashMap(myHash3);

	hashmap<string, int> myHash4 = myHash;
	printHashMap(myHash4);

	map<string, int> myMap2(myHash.begin(), myHash.end());
	for (map<string, int>::iterator it = myMap2.begin(); it != myMap2.end(); ++it)
	{
		cout << it->first << " STL maps to " << (*it).second << endl;
	}
	cout << endl;

	myHash.erase("KeyFour");
	printHashMap(myHash);

	myHash.erase("KeySix");
	printHashMap(myHash);

	printHashMap(myHash2);
	myHash2.erase(myHash2.begin() + 1);
	printHashMap(myHash2);

	myHash2.erase(myHash2.end() - 1);
	printHashMap(myHash2);

	myHash2.erase(myHash2.end() - 1);
	printHashMap(myHash2);

	cout << boolalpha << myHash2.empty() << endl;
	
	myHash3.erase(myHash3.begin(), myHash3.end());
	cout << boolalpha << myHash3.empty() << endl;
	
	myHash.clear();
	cout << boolalpha << myHash.empty() << endl;

	return 0;
}

void printHashMap(const hashmap<string, int>& myMap)
{
	for (hashmap<string, int>::iterator it = myMap.begin(); it != myMap.end(); ++it)
	{
		cout << it->first << " maps to " << (*it).second << endl;
	}

	cout << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值