C++模拟实现unordered_map和unordered_set

unordered系列

  • unordered_map是存储键值对的关联式容器,其允许通过key快速的索引到与其对应的value。
  • 在内部unordered_map将相同哈希值的键值对放在相同的桶中。键值通常用于惟一地标识元素,而映射值是一个对象,其内容与此键关联。键和映射值的类型可能不同。
  • unordered_map容器通过key访问单个元素要比map快,map是用红黑树实现的,时间复杂度为lgN。但unordered_map通常在遍历元素子集的范围迭代方面效率较低。
  • unordered_set是存储< key >的关联式容器,它不支持operator[]操作,其他操作和unoredred_map类似,底层结构也都是相同的。

底层结构

  • unordered系列的关联式容器之所以效率比较高,是因为其底层使用了哈希结构。
  • 这里我使用开散列解决哈希冲突问题。
  • 开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

完整代码请前往GitHub—>点我啊

HashBucket.hpp

#pragma once
#include
#include"Common.hpp"

template<class T>
struct HashNode {
	HashNode(const T& data = T())
		:_pNext(nullptr)
		,_data(data)
	{}
	HashNode<T>* _pNext;
	T _data;              
};

template<class T, class KorV, class DF = DFStr>
class HashBucket;

template<class T, class KorV,class DF = DFStr>
struct Iterator {
	typedef HashNode<T> Node;
	typedef Iterator<T, KorV, DF> Self;

	Iterator(Node* pNode = nullptr, HashBucket<T, KorV, DF>* ht = nullptr)
		:_pNode(pNode)
		,_ht(ht)
	{}
	T& operator*() {
		return _pNode->_data;
	}
	T* operator->() {
		return &(_pNode->_data);
	}
	Self& operator++() {
		Next();
		return *this;
	}
	Self operator++(int) {
		Self tmp(_pNode);
		Next();
		return tmp;
	}
	bool operator==(Self& t) {
		return _pNode == t._pNode;
	}
	bool operator!=(Self& t) {
		return _pNode != t._pNode;
	}
	void Next() {
		if (_pNode->_pNext) {
			_pNode = _pNode->_pNext;
		}
		else {
			size_t addr = _ht->HashFunc(_pNode->_data);
			for (int i = addr + 1; i < _ht->_arr.size(); ++i) {
				if (_ht->_arr[i]) {
					_pNode = _ht->_arr[i];
					return;
				}
			}
			_pNode = nullptr;
		}
	}
	Node* _pNode;
	HashBucket<T, KorV, DF>* _ht;
};

template<class T, class KorV, class DF>
class HashBucket {
public:
	typedef HashNode<T> Node;
	typedef HashBucket<T, KorV, DF> Self;
	typedef Iterator<T, KorV, DF> iterator;
	friend struct Iterator<T, KorV, DF>;
public:
	HashBucket(size_t size = 11)
		:_size(0)
	{
		_arr.resize(size);
	}
	~HashBucket() {
		Clear();
	}
	std::pair<iterator, bool> Insert(const T& data) {
		CheckCapacity();

		size_t addr = HashFunc(data);

		//查找是否有重复节点
		Node* ptr = _arr[addr];
		while (ptr) {
			if (KorV()(ptr->_data) == KorV()(data))   
				return make_pair(iterator(ptr, this), false);
			ptr = ptr->_pNext;
		}

		ptr = new Node(data);
		ptr->_pNext = _arr[addr];
		_arr[addr] = ptr;
		++_size;
		return make_pair(iterator(ptr, this), true);
	}
	size_t Erase(const T& data) {
		size_t addr = HashFunc(data);
		Node* ptr = _arr[addr];
		Node* pre = nullptr;
		while (ptr) {
			if (ptr->_data == data) {
				if (!pre) //删除头结点
					_arr[addr] = ptr->_pNext;
				else //删除中间节点
					pre->_pNext = ptr->_pNext;
				delete ptr;
				--_size;
				return 1;
				
			}
			else {
				pre = ptr;
				ptr = ptr->_pNext;
			}
		}
		return 0;
	}
	iterator find(const T& data) const{
		size_t addr = HashFunc(data);
		Node* ptr = _arr[addr];
		while (ptr) {
			if (KorV()(ptr->_data) == KorV()(data))
				return iterator(ptr, this);
			ptr = ptr->_pNext;
		}
		return iterator(nullptr, this);
	}
	size_t size() const{
		return _size;
	}
	bool empty()const {
		return _size == 0;
	}
	iterator begin() {
		for (int i = 0; i < _arr.size(); ++i) {
			if (_arr[i]) {
				return iterator(_arr[i], this);
			}
		}
		return iterator(nullptr, this);
	}
	iterator end() {
		return iterator(nullptr, this);
	}
	void Clear() {
		for (size_t i = 0; i < _arr.size(); ++i) {
			Node* ptr = _arr[i];
			while (ptr) {
				_arr[i] = ptr->_pNext;
				delete ptr;
				ptr = _arr[i];
			}
		}
		_size = 0;
	}
	size_t bucket_count() const{
		return _arr.size();
	}
	size_t bucket_size(size_t n) const{
		if (n >= _arr.size())
			return 0;
		size_t count = 0;
		Node* ptr = _arr[n];
		while (ptr) {
			++count;
			ptr = ptr->_pNext;
		}
		return count;
	}
	size_t bucket(const T& data) {
		return HashFunc(data);
	}
	void Swap(Self& t) {
		_arr.swap(t._arr);
		std::swap(_size, t._size);
	}
private:
	void CheckCapacity() {    //扩容
		if (_size == _arr.size()) {
			size_t newSize = GetNextPrime(_arr.size());
			Self newBucket(newSize);
			for (size_t i = 0; i < _arr.size(); ++i) {
				Node* ptr = _arr[i];
				while (ptr) {
					size_t addr = newBucket.HashFunc(ptr->_data);
					_arr[i] = ptr->_pNext;
					ptr->_pNext = newBucket._arr[addr];
					newBucket._arr[addr] = ptr;
					++newBucket._size;
					ptr = _arr[i];
				}
			}
			Swap(newBucket);
		}
	}
	size_t HashFunc(const T data) const{
		return DF()(KorV()(data)) % _arr.size();
	}
private:
	std::vector<Node*>  _arr;
	size_t _size;
};

Unordered_map.hpp

#pragma once
#include"HashBucket.hpp"

template<class K,class V>
class Unordered_map {
	typedef std::pair<K, V> ValueType;
	typename typedef HashBucket<ValueType, KORV>::iterator iterator;
	struct KORV 
	{
		const K& operator()(const ValueType& data)const {
			return data.first;
		}
	};
public:
	Unordered_map(size_t size = 11)
		:_ht(size)
	{}
	iterator begin(){
		return _ht.begin();
	}
	iterator end(){
		return _ht.end();
	}
	bool empty()const {
		return _ht.empty();
	}
	size_t size()const {
		return _ht.size();
	}
	std::pair<iterator,bool> insert(const ValueType& data){
		return _ht.Insert(data);
	}
	size_t erase(const K& key){
		return _ht.Erase(ValueType(key,V()));
	}
	iterator find(const K& key) const{
		return _ht.find(ValueType(key, V()));
	}
	void clear() {
		_ht.Clear();
	}
	void swap(const Unordered_map<K,V>& m) {
		_ht.Swap(m._ht);
	}
	V& operator[](const K& k) {
		return (*(insert(ValueType(k, V())).first)).second;
	}
	size_t buck_count()const {
		return _ht.bucket_count();
	}
	size_t buck_size(size_t n)const {
		return _ht.bucket_size(n);
	}
	size_t bucket(const K& k) {
		return _ht.bucket(ValueType(k, V()));
	}
private:
	HashBucket<ValueType, KORV> _ht;
};

Unordered_set.hpp

#pragma once
#include"HashBucket.hpp"

template<class K>
class Unordered_set {
	typedef K ValueType;
	typename typedef HashBucket<ValueType, KORV>::iterator iterator;
	struct KORV
	{
		const ValueType& operator()(const ValueType& data)const {
			return data;
		}
	};
public:
	Unordered_set(size_t size = 11)
		:_ht(size)
	{}
	iterator begin() {
		return _ht.begin();
	}
	iterator end() {
		return _ht.end();
	}
	bool empty()const {
		return _ht.empty();
	}
	size_t size()const {
		return _ht.size();
	}
	std::pair<iterator, bool> insert(const ValueType& data) {
		return _ht.Insert(data);
	}
	size_t erase(const ValueType& key) {
		return _ht.Erase(key);
	}
	iterator find(const ValueType& key) const {
		return _ht.find(key);
	}
	void clear() {
		_ht.Clear();
	}
	void swap(const Unordered_set<K>& m) {
		_ht.Swap(m._ht);
	}
	size_t buck_count()const {
		return _ht.bucket_count();
	}
	size_t buck_size(size_t n)const {
		return _ht.bucket_size(n);
	}
	size_t bucket(const ValueType& k) {
		return _ht.bucket(k);
	}
private:
	HashBucket<ValueType, KORV> _ht;
};

你可能感兴趣的:(C++模拟实现unordered_map和unordered_set)