189 8069 5689

c#如何实现哈希表线性探测

这篇文章主要介绍了c#如何实现哈希表线性探测,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

成都创新互联服务项目包括侯马网站建设、侯马网站制作、侯马网页制作以及侯马网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,侯马网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到侯马省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

    HashTable-散列表/哈希表,是根据关键字(key)而直接访问在内存存储位置的数据结构。

   它通过一个关键值的函数将所需的数据映射到表中的位置来访问数据,这个映射函数叫做散列函数,存放记录的数组叫做散列表。

  • 哈希冲突/哈希碰撞

    不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突。任意的散列函数都不能避免产生冲突。

   我给大家介绍的是哈希表的线性探测,线性探测的基本思路:

       1.用一个数据除以散列表的长度,余数是多少,就把这个数放在散列表下标相同的地方。

       2.如果发生哈希冲突,就看下一个位置是否有数据,一直到没有哈希冲突,就把这个数据放在此位置。

       3.如果已经试探到最后一个位置,但前面还有位置没有试探,那么我们就从开始位置继续试探,直到全部位置试探成功。

实现代码:

Hash.h中

//哈希表中存放数据的状态
enum State
{
	EMPTY,//没有数据
	DELETE,//删除数据后
	EXIST//有数据
};
template 
class HashTable
{
public:
	//构造函数
	HashTable()
		:_table(NULL)
		, state(NULL)
		, _size(0)
		, _capatity(0)
	{}
	//构造函数
	HashTable(size_t size)
		:_table(new K[size])
		, _state(new State[size])
		, _capatity(size)
		, _size(0)
	{
		for (int i = 0; i < _capatity; i++)
		{
			_state[i] = EMPTY;
		}
	}
	//插入数据
	bool Insert(const K& key)
	{
		//检测静态哈希表是否已满
		if (_size == _capatity)
		{
			cout << "哈希表已满!" << endl;
			return false;
		}
		int index = _HashFunc(key);
		while (_state[index] == EXIST)
		{
			index++;//哈希冲突,找下一个位置
			//最后一个位置有数据,从头开始找位置
			if (index == _capatity)
			{
				index = 0;
			}
		}
		//哈希不冲突,直接放数据
		_table[index] = key;
		_state[index] = EXIST;
		_size++;
		return true;
	}
	//查找
	int Find(const K& key)
	{
		int index = _HashFunc(key);
		while (_state[index] != EMPTY)
		{
			//找到元素
			if (_table[index] == key&&_state[index] == EXIST)
			{
				return index;
			}
			//如果算出的位置,不是要找的元素,index++;
			index++;
			//最后一个位置不是,就从头开始找
			if (index == _capatity)
			{
				index = 0;
			}
		}
		return -1;
	}
	void print()
	{
		for (int i = 0; i < _capatity; i++)
		{
			if (_state[i] == EXIST)
			{
				printf("[%d]EXIST:%d\n",i, _table[i]);
			}
			else if (_state[i] == DELETE)
			{
				printf("[%d]DELETE:NULL\n", i, _table[i]);
			}
			else
			{
				printf("[%d]EMPTY:NULL\n", i);
			}
		}
	}
	//删除某一位置元素
	bool Remove(const K& key)
	{
		int index = Find(key);//找到这个元素
		//删除这个元素
		if (index != -1)
		{
			_state[index] = DELETE;
			_size--;
			return true;
		}
		return false;
	}
protected:
	//算出数据在哈希表中的位置(哈希不冲突)
	int _HashFunc(const K& key)
	{
		return key%_capatity;
	}
protected:
	K* _table;//数组
	State* _state;//状态数组
	size_t _size;//数组大小
	size_t _capatity;//数组的容量
};

test.cpp中

#include 
using namespace std;
#include "Hash.h"
void Test()
{
	HashTable ht(10);
	ht.Insert(24);
	ht.Insert(20);
	ht.Insert(36);
	ht.Insert(23);
	ht.Insert(30);
	ht.print();

	int ret = ht.Find(30);
	cout << "下标为:"<

上面的代码有不完善的地方,我们在处理哈希问题是,有这样的问题存在。散列表载荷因子的问题。

    载荷因子=填入表中的元/散列表的长度

   载荷因子与“填在表中元素的个数”成正比,载荷因子越大,填入表中的元素越多,产生冲突的可能性越大。反之,则相反。

    载荷因子应该限制在0.7—0.8以下,超过0.8,查找CPU缓存不命中,效率就比较低,所以一般载荷因子为0.8就应该扩容。

   所以上面的检查容量应该稍微改一下

代码:

bool Insert(const K& key)
	{
		//检测静态哈希表是否已满
		/*if (_size == _capatity)
		{
			cout << "哈希表已满!" << endl;
			return false;
		}*/
		//考虑到载荷因子在0.7~0.8一下比较好,这样检查容量比较好
		if (10 * _size >= 8 * _capatity)
		{
			_CheckCapatity();
		}
		int index = _HashFunc(key);
		while (_state[index] == EXIST)
		{
			index++;//哈希冲突,找下一个位置
			//最后一个位置有数据,从头开始找位置
			if (index == _capatity)
			{
				index = 0;
			}
		}
		//哈希不冲突,直接放数据
		_table[index] = key;
		_state[index] = EXIST;
		_size++;
		return true;
	}
	
	//交换
	void _Swap(HashTable tmp)
	{
		swap(_size, tmp._size);
		swap(_capatity, tmp._capatity);
		swap(_state, tmp._state);
		swap(_table, tmp._table);
	}
	//检查容量
	void _CheckCapatity()
	{
		HashTable tmp(2 * _capatity);
		for (int i = 0; i < _capatity; i++)
		{
			tmp.Insert(_table[i]);
		}
		_Swap(tmp);
	}

上面只能存储数据,如果是字符串,怎么办哪?所以我们想处理字符串,可以写一个自定义类型,然后利用特化来处理字符串。

代码如下:

#include 
//哈希表中存放数据的状态
enum State
{
	EMPTY,//没有数据
	DELETE,//删除数据后
	EXIST//有数据
};
template 
//处理
struct DefaultFunc
{
	size_t operator()(const K& key)
	{
		return key;
	}
};
//自定义类型
template<>
struct DefaultFunc//特化
{
	size_t value = 0;
	size_t operator()(const string& str)
	{
		for (int i = 0; i < str.size(); i++)
		{
			value += str[i];
		}
		return value;
	}
};
template class HashFunc = DefaultFunc>
class HashTable
{
public:
	//构造函数
	HashTable()
		:_table(NULL)
		, state(NULL)
		, _size(0)
		, _capatity(0)
	{}
	//构造函数
	HashTable(size_t size)
		:_table(new K[size])
		, _state(new State[size])
		, _capatity(size)
		, _size(0)
	{
		for (int i = 0; i < _capatity; i++)
		{
			_state[i] = EMPTY;
		}
	}
	//插入数据
	bool Insert(const K& key)
	{
		//检测静态哈希表是否已满
		/*if (_size == _capatity)
		{
			cout << "哈希表已满!" << endl;
			return false;
		}*/
		//考虑到载荷因子在0.7~0.8一下比较好,这样检查容量比较好
		if (10 * _size >= 8 * _capatity)
		{
			_CheckCapatity();
		}
		int index = _HashFunc(key);
		while (_state[index] == EXIST)
		{
			index++;//哈希冲突,找下一个位置
			//最后一个位置有数据,从头开始找位置
			if (index == _capatity)
			{
				index = 0;
			}
		}
		//哈希不冲突,直接放数据
		_table[index] = key;
		_state[index] = EXIST;
		_size++;
		return true;
	}
	//查找
	int Find(const K& key)
	{
		int index = _HashFunc(key);
		while (_state[index] != EMPTY)
		{
			//找到元素
			if (_table[index] == key&&_state[index] == EXIST)
			{
				return index;
			}
			//如果算出的位置,不是要找的元素,index++;
			index++;
			//最后一个位置不是,就从头开始找
			if (index == _capatity)
			{
				index = 0;
			}
		}
		return -1;
	}
	void print()
	{
		/*for (int i = 0; i < _capatity; i++)
		{
			if (_state[i] == EXIST)
			{
				printf("[%d]EXIST:%d\n",i, _table[i]);
			}
			else if (_state[i] == DELETE)
			{
				printf("[%d]DELETE:NULL\n", i, _table[i]);
			}
			else
			{
				printf("[%d]EMPTY:NULL\n", i);
			}
		}*/
		for (int i = 0; i < _capatity; i++)
		{
			if (_state[i] == EXIST)
			{
				cout << i <<"-"<< "EXIST:" << _table[i] << endl;
			}
			else if (_state[i] == DELETE)
			{
				cout << i <<"-"<< "DELETE:" << "NULL" << endl;
			}
			else
			{
				cout << i <<"-"<< "EMPTY:" << "NULL" << endl;
			}
		}
	}
	//删除某一位置元素
	bool Remove(const K& key)
	{
		int index = Find(key);//找到这个元素
		//删除这个元素
		if (index != -1)
		{
			_state[index] = DELETE;
			_size--;
			return true;
		}
		return false;
	}
protected:
	//算出数据在哈希表中的位置(哈希不冲突)
	/*int _HashFunc(const K& key)
	{
		return key%_capatity;
	}*/
	int _HashFunc(const K& key)
	{
		HashFunc ht;
		return ht(key) % _capatity;
	}
	//交换
	void _Swap(HashTable tmp)
	{
		swap(_size, tmp._size);
		swap(_capatity, tmp._capatity);
		swap(_state, tmp._state);
		swap(_table, tmp._table);
	}
	//检查容量
	void _CheckCapatity()
	{
		HashTable tmp(2 * _capatity);
		for (int i = 0; i < _capatity; i++)
		{
			tmp.Insert(_table[i]);
		}
		_Swap(tmp);
	}
protected:
	K* _table;//数组
	State* _state;//状态数组
	size_t _size;//数组大小
	size_t _capatity;//数组的容量
};

test.cpp中

#include 
using namespace std;
#include "Hash.h"
//void Test()
//{
//	HashTable ht(10);
//	ht.Insert(24);
//	ht.Insert(20);
//	ht.Insert(36);
//	ht.Insert(23);
//	ht.Insert(30);
//	ht.print();
//
//	int ret = ht.Find(30);
//	cout << "下标为:"< ht(10);
	ht.Insert("杭哥");
	ht.Insert("张哥");
	ht.Insert("詹姐");
	ht.Insert("亮哥");
	ht.Insert("蛋蛋");
	ht.print();

	int ret = ht.Find("蛋蛋");
	cout << "下标为:" << ret << endl;

	ht.Remove("亮哥");
	ht.print();
}
int main()
{
	//Test();
	Test1();
	system("pause");
	return 0;
}

感谢你能够认真阅读完这篇文章,希望小编分享的“c#如何实现哈希表线性探测”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!


本文名称:c#如何实现哈希表线性探测
网址分享:http://cdxtjz.cn/article/jjsddp.html

其他资讯