key形式哈希表的线性探测

一、什么是key形式的哈希表

简单的说就是通过key的来查找key的值

二、线性探测

简单的来说就是遇到哈西冲突就查找下一个位置,看位置上是否有数据,假如有则继续查找,假如没有则将数据放入到当前位置
局限性:引发洪水式的冲突,冲突越来越多,找的越来越慢(因为找到的是一片冲突,找到空才停下来),效率低

二、定义状态数组和仿函数

1、定义状态数组

由于哈希表中每个位置的传值不知道设置为什么具体的值好并且删除后不知道设置成什么具体的值好(设置为-1万一保存的就是-1呢),所以设置一个状态数组用来,表示每一个为值上的值的状态,初始时设置为EMPTY,当前位置上存在数字设置为EXIST,要删除当前位置上的值设置为DELETE(也为懒删除法)

enum Status  
{  
    EXIST,  
    DELETE,  
    EMPTY,  
};  

2.定义仿函数

定义放函数的作用主要还是提高代码的复用性,对于不同类型的数据,其处理的函数是不同的,而其他地方的代码都是相似的,这样就可以定义一个仿函数专门来处理哈希函数不同的问题

//仿函数
template<class K>
struct DefaulstHashFuncer
{
	size_t operator()(const K& key)
	{
		return key;
	}
};



template<>
struct DefaulstHashFuncer <string>//特化string类型的仿函数
{

	static size_t BKDRHash(const char * str)//<span style="color:#ff0000;">字符串的哈希算法</span>
	{
		unsigned int seed = 131; // 31 131 1313 13131 131313
		unsigned int hash = 0;
		while (*str)
		{
			hash = hash * seed + (*str++);
		}
		return (hash & 0x7FFFFFFF);
	}

	size_t operator()(const string& str)
	{
		return BKDRHash(str.c_str());
	}
};

三、具体实现

1、函数的声明

template<class K, class HashFuncer = DefaulstHashFuncer<K>>
class HashTaable
{
public:
	HashTaable();
	HashTaable(size_t size);
	HashTaable(const HashTaable<K, HashFuncer>& ht);
	HashTaable<K, HashFuncer>& operator=(HashTaable<K, HashFuncer> ht);
	~HashTaable();

public:
	bool Insert(const K& key);
	bool Find(const K& key);
	bool Remove(const K& key);
	void PrintTable();
	void Swap(HashTaable<K>& ht);

protected:
	size_t _HashFunc(const K& key);//哈希函数
	int _Find(const K& key);
	void _CheckCapacity();

protected:
	K* _tables;
	rsize_t _size;
	Status* _status;//状态数组
	size_t _capacity;
};

2、具体实现

(1)默认构造函数

HashTaable()
	:_tables(NULL)
	, _status(NULL)
	, _size(0)
	, _capacity(0)
{}

(2)构造函数,传入构造的哈希表的大小

HashTaable(size_t size)
	:_tables(new K[size])
	, _status(new Status[size])
	, _size(0)
	, _capacity(size)
{
	//for (_status, EMPTY, sizeof(_status)*_size);//枚举类型不能用memsete因为memset是按字节处理
	for (size_t i = 0; i < _capacity; ++i)//若用memset则里面为随机值
	{
		_status[i] = EMPTY;
	}
}

(3)拷贝构造函数

HashTaable(const HashTaable<K, HashFuncer>& ht)
	:_tables(NULL)
	, _status(NULL)
	, _size(0)
	, _capacity(0)
{
	HashTaable<K, HashFuncer> tmp(ht._capacity);
	for (size_t i = 0; i <ht._capacity; ++i)
	{
		if (ht._status[i] == EXIST)//状态为删除时不用管
		{
			tmp.Insert(ht._tables[i]);
		}
	}
	this->Swap(tmp);//冲突改变,相对位置改变
}

(4)operator=

HashTaable<K, HashFuncer>& operator=(HashTaable<K, HashFuncer> ht)
{
	this->Swap(ht);
	return *this;
}
(5)析构函数

~HashTaable()
{
	if (_tables!=NULL)
	{
		delete[] _tables;
		delete[] _status;
		_tables = NULL;
		_status = NULL;
	}
}
(6)插入数据(如果数据本身在表中就存在,则返回false)

bool Insert(const K& key)
{
	/*if (_size == _capacity)
	{
		cout << "Full" << endl;
		return false;
	}*/

	_CheckCapacity();

	size_t index = _HashFunc(key);
	//线性探测
	while (_status[index] == EXIST)
	{
		if (_tables[index] == key)
		{
			return false;
		}
		++index;
		if (index == _capacity)
		{
			index = 0;
		}
	}
	_status[index] = EXIST;
	_tables[index] = key;
	++_size;
	return true;
}

(7)寻找数据

如果找到则返回true,没有找到返回false

bool Find(const K& key)
{
	if (_Find(key) == -1)
	{
		return false;
	}
	return true;
}

(8)删除某个记录

使用懒删除法

bool Remove(const K& key)
{
	int index = _Find(key);
	if (index!=-1)
	{
		_status[index] = DELETE;
		return true;
	}
	return false;
}
(9)打印整个哈希表

void PrintTable()
{
	for (size_t i = 0; i < _capacity; ++i)
	{
		if (_status[i] == EXIST)
		{
			printf("[%d];E->", i);
			cout << _tables[i] << endl;
		}
		else if (_status[i]==DELETE)
		{
			printf("[%d];D->", i);
			cout <<_tables[i];
		}
		else
		{
			printf("[%d];N", i);
			cout << endl;
		}
	}
}

(10)两个哈希表之间发生交换

void Swap(HashTaable<K>& ht)
{
	std::swap(_tables, ht. _tables);
	std::swap(_size, ht._size);
	std::swap(_status, ht._status);
	std::swap(_capacity, ht._capacity);
}

下面为保护的函数


(11)哈希函数
size_t _HashFunc(const K& key)//哈希函数
{
	HashFuncer hf;
	return hf(key) % _capacity;
}

(13)查找key值所在的位置

int _Find(const K& key)
{
	size_t index = _HashFunc(key);//默认哈希表中一定是有空余的位置的
	while (_status[index] != EMPTY)
	{
		if (_tables[index] == key&&_status[index] != DELETE)
		{
			return index;
		}
		++index;
		if (index == _capacity)
		{
			index = 0;
		}
	}
	return -1;
}
(14)增容

void _CheckCapacity()
{
	if (_size * 10 >= _capacity * 7)
	{
		HashTaable<K> tmp(2 * _capacity);
		for (size_t i = 0; i < _capacity; ++i)
		{
			if (_status[i] == EXIST)//状态为删除时不用管
			{
				tmp.Insert(_tables[i]);
			}
		}
		this->Swap(tmp);//冲突改变,相对位置改变
	}
}

三、测试用例

void Test()
{
	HashTaable<string> ht1(10);//使用仿函数解决这个问题
	ht1.Insert("小明");
	ht1.Insert("杰克");

	ht1.Insert("明小");
	ht1.Insert("小军");
	

	ht1.PrintTable();
	cout << endl;
	HashTaable<string> ht2(ht1);
	ht2.Insert("123");
	ht2.PrintTable();

	cout << endl;

	ht2 = ht1;
	ht2.PrintTable();
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值