【C++】unordered_map/set实现(哈希)

         1 .模板参数列表的改造

  • unordered_set是 K模型 的容器,unordered_map是 KV模型 的容器。
  • 要想只用一份哈希表代码同时封装出K模型和KV模型的容器,我们就要对哈希表的模板参数进行控制。
  • 为了与原哈希表的模板参数进行区分,这里将哈希表的第二个模板参数的名字改为T。
template >
class HashBucket;
  •  K:关键码类型
  • V: 不同容器V的类型不同,如果是unordered_map,V代表一个键值对,如果是unordered_set,V 为 K

unordered_set:

template
class unordered_set
{
   
public:
	//...
private:
//传入底层哈希表的是K和K
	HashTable _ht; 
};

unordered_map :注意这里V里面的K要加const,因为K是不可更改的

template
class unordered_map
{
   
public:
	//...
private:
	HashTable> _ht; //传入底层哈希表的是K以及K和V构成的键值对
};

  • KeyOfValue: 因为V的类型不同,通过value取key的方式就不同,详细unordered_map/set的实现
  • HF: 哈希函数仿函数对象类型,哈希函数使用除留余数法,需要将Key转换为整形数字才能取模

         2 .增加迭代器

迭代器的结构:

有两个成员,一个是节点指针,还有一个是哈希表的指针,只要就是为了方便实现迭代器++遍历哈希表的操作。

模板参数列表的前四个class主要是为了实现普通迭代器和const迭代器,第五个参数就是为了获得T中的key值,是一个仿函数,最后一个模板参数是哈希函数,为了构造出哈希表指针而存在

迭代器基本操作的实现:

template
struct HashIterator
{
//重命名哈希节点
	typedef HashData Node;
//重命名迭代器
	typedef HashIterator self;

//指向哈希节点的指针
	Node* _node;
//指向哈希表的指针
	HashTable* _ht;

	HashIterator(Node* node, HashTable*ht) :_node(node),_ht(ht) {}

//解引用
	Ref operator*()
	{
		return _node->_data;
	}
//重载箭头
	Ptr operator->()
	{
		return &_node->_data;
	}
//前置加加
	self& operator++()
	{
		if (_node->_next)
			_node = _node->_next;
		else
		{
			hash hs;
			KeyOfT kot;
			int hashi = hs(kot(_node->_data)) % _ht->_tables.size();
			int i = hashi + 1;
			for (; i < _ht->_tables.size(); i++)
			{
				if (_ht->_tables[i])
				{
					_node = _ht->_tables[i];
					break;
				}
			}
			if(_ht->_tables.size() == i)
			_node = nullptr;
		}
		return *this;
	}
//重载!=
	bool operator!=(const self& l)
	{
		return _node != l._node;
	}

};

哈希表内部改造:

template
class HashTable
{
//注意这里需要声明友元才行
//因为迭代器里面有指向哈希表的指针
//这里可以采用内部内的方法
	friend HashIterator;
public:
//普通迭代器
	typedef HashIterator iterator;
//const迭代器
	typedef HashIterator const_iterator;
//节点指针
	typedef HashData Node;
//迭代器
	HashTable(int n = 10)
	{
		_tables.resize(n,nullptr);
	}
	iterator begin()
	{
		for (int i = 0; i < _tables.size(); i++)
		{
			if (_tables[i])
				return iterator(_tables[i],this);
		}
		return iterator(nullptr,this);
	}
	const_iterator begin()const
	{
		for (int i = 0; i < _tables.size(); i++)
		{
			if (_tables[i])
				return iterator(_tables[i], this);
		}
		return iterator(nullptr, this);
	}
	iterator end()
	{
		return iterator(nullptr, this);
	}	
	const_iterator end()const
	{
		return iterator(nullptr, this);
	}
//插入
	std::pair insert(const T& data)
	{
		KeyOfT kot;
		iterator ret = Find(kot(data));
		if(ret!=end())//这里的!=重载的时候必须加const
			return std::make_pair(ret, false);
		//哈希桶不需要线性探测,挂过去就行了
		hash hs;
		Node* newnode = new Node(data);
		int hashi = hs(kot(data)) % _tables.size();
		newnode->_next = _tables[hashi];
		_tables[hashi] = newnode;
		_n++;
		//判断是否需要扩容
		if (_n * 10 / _tables.size()  > 8)
		{
			HashTable newHT(_tables.size()*2);
			//采用挪动节点的方法,减少消耗
			for (auto& head : _tables)
			{
				Node* cur = head;
				while (cur)
				{
					Node* next = cur->_next;
					int hashi = hs(kot(cur->_data)) % newHT._tables.size();
					cur->_next = newHT._tables[hashi];
					newHT._tables[hashi] = cur;
					cur = next;
				}
				head = nullptr;
			}
			_tables.swap(newHT._tables);
		}
		return std::make_pair(iterator(newnode, this), true);
	}
	iterator Find(const K& data)
	{
		hash hs;
		KeyOfT kot;
		int hashi = hs(data) % _tables.size();
		if (_tables[hashi])
		{
			Node* cur = _tables[hashi];
			while (cur)
			{
				if (kot(cur->_data) == data)return iterator(cur,this);
				cur = cur->_next;
			}
		}
		return iterator(nullptr,this);
	}
//删除
	bool Erase(const K& key)
	{
		hash hs;
		KeyOfT kot;
		int hashi = hs(key) % _tables.size();
		if (_tables[hashi])
		{
			Node* cur = _tables[hashi];
			Node* parent = nullptr;
			while (cur)
			{
				if (kot(cur->_data) == key)
				{
					if (parent)
						parent->_next = cur->_next;
					else
						_tables[hashi] = cur->_next;
					delete cur;
					cur = nullptr;
					--_n;
					return true;
				}
				parent = cur;
				cur = cur->_next;
			}
			return false;
		}
	}
//析构
	~HashTable()
	{
		for (auto head : _tables)
		{
			Node* cur = head;
			while (cur)
			{
				Node* next = cur->_next;
				delete cur;
				cur = next;
			}
			head = nullptr;
		}
	}
private:
//这里用vector来存储节点(节点是用链表存储
	std::vector*> _tables;
	int _n = 0;
};

         3 . unordered_map

封装unordered_map:

template
//哈希函数,很多类型需要自己实现
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return size_t(key);
	}
};
//string经常使用,搞一个特化版本
template<>
struct HashFunc
{
	size_t operator()(const std::string& str)
	{
		int hash = 0;
		for (auto e : str)
		{
			hash *= 131;
			hash += e;
		}
		return hash;
	}
};
//使用unordered_map需要传入哈希函数,也有类型是默认的
template>
class unordered_map
{

public:
//用来取比较大小的key
	struct KeyOfT
	{
		const K& operator()(const std::pair& d)
		{
			return d.first;
		}
	};
	typedef typename HashTable, KeyOfT, hash>::iteratiterator;
//这里不认识iterator是因为没有实例化
//编译器不知道他是类还是什么
//加tepename是为了告诉编译器他是一个类型
	typedef typename HashTable::const_iterator 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();
	}
//实现插入
	std::pair insert(const std::pair& data)
	{
		auto ret = _ht.insert(data);
		return ret;
	}
	bool erase(const K& key)
	{
		return _ht.Erase(key);
	}
//重载[]
//没有就插入并返回——值
//有就返回——值
	V& operator[](const K& key)
	{
		auto ret = _ht.insert(std::make_pair(key, V()));
		return ret.first->second;
	}
//查找返回迭代器
	iterator find(const K& key)
	{
		return _ht.Find(key);
	}
private:
	HashTable, KeyOfT, hash> _ht;
};

         4 . unordered_set

封装unordered_set:与上面unordered_map类似

template
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return size_t(key);
	}
};
template<>
struct HashFunc
{
	size_t operator()(const std::string& str)
	{
		int hash = 0;
		for (auto e : str)
		{
			hash *= 131;
			hash += e;
		}
		return hash;
	}
};
template>
class unordered_set
{
	struct KeyOfT
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};
public:
	typedef typename HashTable::iterator iterator;
	typedef typename HashTable::const_iterator 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();
	}
	std::pair insert(const K& key)
	{
		return _ht.insert(key);
	}
	bool erase(const K& key)
	{
		return _ht.Erase(key);
	}
	iterator find(const K& key)
	{
		return _ht.Find(key);
	}
private:
	HashTable _ht;
};

你可能感兴趣的:(C++,c++,哈希算法,开发语言)