哈希(构造哈希函数)

哈希

哈希也可以叫散列

画一个哈希表

 

 哈希冲突越多,哈希表效率越低。

闭散列开放定址法:

1.线性探测,依次往后去找下一个空位置。

2.二次探测,按2次方往后找空位置。

#pragma once
#include<vector>
#include<iostream>
#include<string>
#include<unordered_map>
using namespace std;
template<class K>
struct SetKeyOfT
{
	const K& operator()(const K& key)
	{
		return key;
	}
};
//unordered_set<K>  ->HashTable<K,K>
//unordered_map<K,V>   ->HashTable<K,pair<K,V>>
enum State
{
	EMPTY,
	EXITS,
	DELETE,	
};
template<class T>
struct HashData//解决:该位置原来就是空还是删除后变为了空
{
	T _data;
	State _state;
};
template<class K,class T,class KeyOfT>
class HashTable//冲突了一定是连续的,但是删除会影响查找,所以应该设置状态标志。将T替换为HashData
{
	typedef HashData<T> HashData;
public:
	bool Insert(const T& d)
	{
		KeyOfT koft;
		//负载因子=表中数据/表的大小  衡量哈希表满的程度
		//表越接近满,插入数据越容易冲突,冲突越多,效率越低。
		//哈希表并不是满了才增容,开放定址法中,一般负载因子到了0.7左右就开始增容
		//负载因子越小,冲突概率越低,整体效率越高,但是负载因子越小,浪费的空间越大。
		//所以负载因子一般去折中值
		if (_tables.size()==0||_num*10/_tables.size()>=7)
		{
			//增容
			//1.开二倍大小的新表
			//2.遍历旧表中的数据,确定数据在新表中的映射位置
			//3.释放旧表
			vector<HashData> newtables;
			size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
			newtables.resize(_tables.size() * 2);
			for (size_t i = 0; i < _tables.size(); ++i)
			{
				if (_tables[i]._state == EXITS)
				{
					size_t index = koft(_tables[i]._data % newtables.size());
					while (newtables[index]._state == EXITS)
					{
						++index;
						if (index == _tables.size())
						{
							index = 0;
						}
					}
					newtables[index] = _tables[i];
				}
			}
			_tables.swap(newtables);
		}
		//KeyOfT koft;
		//计算d中的key在表中映射的位置
		size_t index = koft(d) % _tables.size();
		//EXITS就进行探测
		while (_tables[index]._state==EXITS)
		{
			if (koft(_tables[index]._data) == koft(d))
				return false;
			++index;
			if (index == _tables.size())
			{
				index = 0;
			}
		}
		_tables[index]._data = d;
		_tables[index]._state = EXITS;
		_num++;
		return true;
	}
	HashData* Find(const K& key)
	{
		KeyOfT koft;
		//计算d在表中映射的位置
		size_t index = key % _tables.size();
		while (_tables[index]._state != EMPTY)
		{
			if (koft(_tables[index]._data) == key)
			{
				if (_tables[index]._state == EXITS)
					return &_tables[index];
				else if (_tables[index]._state == DELETE)
					return nullptr;
			}
			++index;
			if (index == _tables.size())
			{
				index = 0;
			}
		}
		return nullptr;
	}
	bool Erase(const K& key)
	{
		HashData* ret = Find(key);
		if (ret)
		{
			ret->_state = DELETE;
			--_num;
			return true;
		}
		else
		{
			return false;
		}
	}
private:
	vector<HashData> _tables;
	size_t _num=0;//存了几个有效数据
};

void TestHashTable()
{
	
	HashTable<int, int, SetKeyOfT<int>> ht;
	ht.Insert(4);
	ht.Insert(14);
	ht.Insert(24);
	ht.Insert(5);
	ht.Insert(15);
	ht.Insert(25);
	ht.Insert(6);
	ht.Insert(16);
	

}

更优的实现方法

开散列哈希桶:

namespace OPEN_HASH
{
	template<class T>
	struct HashNode
	{
		T _data;
		HashNode<T>* _next;
	};
	template<class K,class T,class KeyOfT>
	class HashTable
	{
	public:
		typedef HashNode<T>* Node;
		bool Insert(const T& data)
		{
			//1.先查找这个值在不在表中
			KeyOfT koft;
			//如果负载因子等于1,则增容,避免大量的哈希冲突
			if (_tables.size == _num)
			{
				//增容
				//1.开二倍大小的新表
				//2.遍历旧表中的数据,确定数据在新表中的映射位置
				//3.释放旧表
				vector<Node> newtables;
				size_t newsize = _tables.size() == 0 ? 10 : _tables.size() * 2;
				newtables.resize(newsize);
				for (size_t i = 0; i < _tables.size(); ++i)
				{
					//将旧表中的结点取下来重新计算在新表中的位置,并插入进去
					Node cur = _tables[i];
					while (cur)
					{
						Node next = cur->_next;
						size_t index = koft(cur->_data) % newtables.size();
						cur->_next = newtables[index];
						newtables[index] = cur;
						cur = next;
					}
					_tables[i] = nullptr;
				}
				_tables[i].swap(newtables);
			}
			//计算数据在表中映射的位置
			size_t index = koft(data) % _tables.size();
			Node cur = _tables[index];
			while (cur)
			{
				if (koft(cur->_data) == koft(data))
					return false;
				else
					cur = cur->next;
			}
			//2.头插到挂的链表中
			Node newnode = new Node(data);
			newnode->next = _tables[index];
			_tables[index] = newnode;
			++_num;
			return true;
		}
		Node* Find(const K& key)
		{
			KeyOfT koft;
			size_t index = key % _tables.size();
			Node cur = _tables[index];
			while (cur)
			{
				if (koft(cur->_data) == key)
				{
					return cur;
				}
				else return cur->_next;
			}
			return nullptr;
		}
		bool Erase(const K& key)
		{
			KeyOfT koft;
			size_t index = key % _tables.size();
			Node prev = nullptr;
			Node cur = _tables[index];
			while (cur)
			{
				if (koft(cur->_data) == key)
				{
					if (prev == nullptr)
						//表示要删的值在一个结点
						_tables[index] = cur->_next;
					else
						prev->_next = cur->_next;
					delete cur;
					return true;
				}
				else
				{
					prev = cur;
					cur = cur->_next;
				}
			}
			return false;
		}
	private:
		vector<Node> _tables;
		size_t _num=0;//记录表中存储的数据个数
	};
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值