29 unordered_set和unordered_map

用哈希结构封装map和set

哈希表的改造

节点

数据类型改为模板
在这里插入图片描述

迭代器

成员

一个节点的指针,哈希表和下标用来++访问,哈希表需要支持修改,传入指针,const为了常迭代器可以传递哈希表
在这里插入图片描述

++

当前节点的next有内容,先遍历完当前桶。否则下标++,寻找下一个不为空的桶

self& operator++()
{
	if (_node->_next)
	{
		//单个桶
		_node = _node->_next;
	}
	else
	{
		
		//下一个桶
		_hashi++;
		while (_hashi < _pht->_table.size())
		{
			if (_pht->_table[_hashi])
			{
				_node = _pht->_table[_hashi];
				break;
			}
			_hashi++;
		}

		//循环结束没有数据
		if (_hashi == _pht->_table.size())
		{
			_node = nullptr;
		}
	}

	return *this;
}

迭代器需要访问哈希表,带上友元
在这里插入图片描述begin返回第一个不为空的桶,end返回空
在这里插入图片描述在这里插入图片描述

凡是数据比较的地方都需要用仿函数
在这里插入图片描述

在这里插入图片描述

#pragma once
#pragma once
#include <string>
#include <iostream>
#include <vector>

template <class T>
struct HashNode
{
	HashNode<T>* _next;
	T _data;

	HashNode(const T& data)
		:_data(data), _next(nullptr)
	{}
};

//hash int
template <class K>
struct HashFunc
{
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};

//字符串模板特化,string
template <>
struct HashFunc<std::string>
{
	size_t operator()(const std::string& key)
	{
		//BKDR方法
		size_t hash = 0;
		for (auto ch : key)
		{
			hash *= 31;
			hash += ch;
		}

		return hash;
	}
};

//前置声明
template <class K, class T, class KeyOfT, class Hash>
class HashBucket;

template <class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
struct __HashIterator
{
	typedef HashNode<T> node;
	typedef __HashIterator<K, T, Ref, Ptr, KeyOfT, Hash> self;

	node* _node;
	const HashBucket<K, T, KeyOfT, Hash>* _pht;
	size_t _hashi;

	__HashIterator(node* node, HashBucket<K, T, KeyOfT, Hash>* pht, size_t hashi)
		:_node(node), _pht(pht), _hashi(hashi)
	{}

	__HashIterator(node* node, const HashBucket<K, T, KeyOfT, Hash>* pht, size_t hashi)
		:_node(node), _pht(pht), _hashi(hashi)
	{}
	
	bool operator!=(const self& x)
	{
		return _node != x._node;
	}

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

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

	self& operator++()
	{
		if (_node->_next)
		{
			//单个桶
			_node = _node->_next;
		}
		else
		{
			
			//下一个桶
			_hashi++;
			while (_hashi < _pht->_table.size())
			{
				if (_pht->_table[_hashi])
				{
					_node = _pht->_table[_hashi];
					break;
				}
				_hashi++;
			}

			//循环结束没有数据
			if (_hashi == _pht->_table.size())
			{
				_node = nullptr;
			}
		}

		return *this;
	}
};

//unordered_set hashpackage<K, K>
//unordered_set hashpackage<K, pair<K ,V>>

//keyoft取出插入数据的key,hash将其他类型转为整形
template <class K, class T, class KeyOfT, class Hash>
class HashBucket
{
	typedef HashNode<T> node;
	//typedef __HashIterator<K, T, KeyOfT, Hash, const T&, const T*> const_iterator;
	template <class K, class T, class Ref, class Ptr, class KeyOfT, class Hash>
	friend struct __HashIterator;
public:
	typedef __HashIterator<K, T, T&, T*, KeyOfT, Hash> iterator;
	typedef __HashIterator<K, T, const T&, const T*, KeyOfT, Hash> const_iterator;
	
	iterator begin()
	{
		for (size_t i = 0; i < _table.size(); i++)
		{
			if (_table[i])
			{
				return iterator(_table[i], this, i);
			}
		}

		//如果都为空
		return end();
	}

	iterator end()
	{
		return iterator(nullptr, this, -1);
	}

	const_iterator begin() const
	{
		for (size_t i = 0; i < _table.size(); i++)
		{
			if (_table[i])
			{
				return const_iterator(_table[i], this, i);
			}
		}	
	}
	//const修饰this,传入const HashBucket对象
	const_iterator end() const
	{
		return const_iterator(nullptr, this, -1);
	}

public:
	HashBucket()
	{
		_table.resize(10);
	}

	std::pair<iterator, bool> insert(const T& data)
	{
		KeyOfT kot;
		iterator it = find(kot(data));
		if (it != end())
		{
			return std::make_pair(it, false);
		}
		
		Hash hf;
		//负载因子,1
		if (_n == _table.size())
		{
			//扩容
			size_t newsize = _table.size() * 2;
			std::vector<node*> newtable;
			newtable.resize(newsize, nullptr);
			//遍历旧表
			for (size_t i = 0; i < _table.size(); i++)
			{
				node* cur = _table[i];
				while (cur)
				{
					node* next = cur->_next;
					//挪动到新表
					size_t hashi = hf(kot(cur->_data)) % newtable.size();
					cur->_next = newtable[hashi];
					newtable[hashi] = cur;

					cur = next;
				}
				//旧表还指向节点,置空
				_table[i] = nullptr;
			}

			_table.swap(newtable);
		}

		//Hash hf;
		size_t hashi = hf(kot(data)) % _table.size();
		node* newnode = new node(data);
		//头插
		newnode->_next = _table[hashi];
		_table[hashi] = newnode;

		_n++;

		return std::make_pair(iterator(newnode, this, hashi), true);
	}

	iterator find(const K& key)
	{
		KeyOfT kot;
		Hash hf;
		//线性探测,字符串需要转整数
		size_t hashi = hf(key) % _table.size();
		node* cur = _table[hashi];
		while (cur)
		{
			if (kot(cur->_data) == key)
			{
				return iterator(cur, this, hashi);
			}
			cur = cur->_next;
		}

		return end();
	}

	bool erase(const K& key)
	{
		KeyOfT kot;
		Hash hf;
		size_t hashi = hf(key) % _table.size();
		node* prev = nullptr;
		node* cur = _table[hashi];
		while (cur)
		{
			//删除
			if (kot(cur->_data) == key)
			{
				if (prev == nullptr)
				{
					_table[hashi] = cur->_next;
				}
				else
				{
					prev->_next = cur->_next;
				}

				delete cur;

				return true;
			}

			prev = cur;
			cur = cur->_next;
		}

		return false;
	}

	void print()
	{
		for (size_t i = 0; i < _table.size(); i++)
		{
			if (_table[i])
			{
				node* cur = _table[i];
				while (cur)
				{
					std::cout << "[" << i << "]->" << cur->_kv.first <<
						":" << cur->_kv.second << " ";

					cur = cur->_next;
				}
				std::cout << std::endl;
			}
			else
			{
				printf("[%d]->\n", i);
			}
		}
	}

	~HashBucket()
	{
		for (size_t i = 0; i < _table.size(); i++)
		{
			node* del = _table[i];
			while (del)
			{
				node* next = del->_next;
				delete del;
				del = next;
			}

			_table[i] = nullptr;
		}
	}

	//桶情况
	void some()
	{
		/*size_t bucketsize = 0;
		size_t maxbucketlen = 0;
		size_t sum = 0;
		double averagebucketlen = 0;

		for (size_t i = 0; i < _table.size(); i++)
		{
			if (_table[i])
			{
				node* cur = _table[i];
				int len = 0;
				while (cur)
				{
					cur = cur->_next;
					len++;
				}

				if (maxbucketlen < len)
				{
					maxbucketlen = len;
				}
				sum += len;
				bucketsize++;
			}
		}

		averagebucketlen = (double)sum / (double)bucketsize;

		printf("哈希表大小:%d\n", _table.size());
		printf("桶大小:%d\n", bucketsize);
		printf("最大桶:%d\n", maxbucketlen);
		printf("平均桶:%lf\n", averagebucketlen);*/
		size_t bucketSize = 0;
		size_t maxBucketLen = 0;
		size_t sum = 0;
		double averageBucketLen = 0;

		for (size_t i = 0; i < _table.size(); i++)
		{
			node* cur = _table[i];
			if (cur)
			{
				++bucketSize;
			}

			size_t bucketLen = 0;
			while (cur)
			{
				++bucketLen;
				cur = cur->_next;
			}

			sum += bucketLen;

			if (bucketLen > maxBucketLen)
			{
				maxBucketLen = bucketLen;
			}
		}

		averageBucketLen = (double)sum / (double)bucketSize;

		printf("插入数据:%d\n", _n);
		printf("all bucketSize:%d\n", _table.size());
		printf("bucketSize:%d\n", bucketSize);
		printf("maxBucketLen:%d\n", maxBucketLen);
		printf("averageBucketLen:%lf\n\n", averageBucketLen);

	}

private:
	std::vector<node*> _table;
	size_t _n = 0;  //个数
};

unordset

K和V都传K,为了保证key不能修改,使用const迭代器,hash字符串转换模板在这一层传入
在这里插入图片描述在这里插入图片描述
插入的返回值是pair,这里哈希表返回的是普通迭代器,需要构造成const迭代器返回

std::pair<const_iterator, bool> insert(const K& key)
{
	auto ret = _ht.insert(key);
	return std::pair<const_iterator, bool>(const_iterator(ret.first._node,
		ret.first._pht, ret.first._hashi), ret.second);
}

#pragma once
#include "hashpackage.h"

template <class K, class Hash = HashFunc<K>>
class unordset
{
	struct SetOfK
	{
		const K& operator()(const K& key)
		{
			return key;
		}
	};

	
public:
	typedef typename HashBucket<K, K, SetOfK, Hash>::const_iterator iterator;
	typedef typename HashBucket<K, K, SetOfK, Hash>::const_iterator const_iterator;
	const_iterator begin() const
	{
		return _ht.begin();
	}

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

	std::pair<const_iterator, bool> insert(const K& key)
	{
		auto ret = _ht.insert(key);
		return std::pair<const_iterator, bool>(const_iterator(ret.first._node,
			ret.first._pht, ret.first._hashi), ret.second);
	}

	iterator find(const K& key)
	{
		return _ht.find(key);
	}

	bool erase(const K& key)
	{
		return _ht.erase(key);
	}

private:
	HashBucket<K, K, SetOfK, Hash> _ht;
};

unordsmap

提供[]运算,返回迭代器的数据
在这里插入图片描述

#pragma once
#include "hashpackage.h"

template <class K, class V, class Hash = HashFunc<K>>
class unordmap
{
	struct SetOfV
	{
		const K& operator()(const std::pair<K, V>& kv)
		{
			return kv.first;
		}
	};
public:
	
	typedef typename HashBucket<K, std::pair<const K, V>, SetOfV, Hash>::iterator iterator;
	iterator begin()
	{
		return _ht.begin();
	}

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

	std::pair<iterator, bool> insert(const std::pair<K, V>& kv)
	{
		return _ht.insert(kv);
	}

	V& operator[](const K& key)
	{
		std::pair<iterator, bool> ret = _ht.insert(std::make_pair(key, V()));
		return ret.first->second;
	}

	const V& operator[](const K& key) const
	{
		std::pair<iterator, bool> ret = _ht.insert(std::make_pair(key, V()));
		return ret.first->second;
	}

	iterator find(const K& key)
	{
		return _ht.find(key);
	}

	bool erase(const K& key)
	{
		return _ht.erase(key);
	}

private:
	HashBucket<K, std::pair<const K, V>, SetOfV, Hash> _ht;
};
  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值