哈希表的线性探测法代码实现

线性表探测法理论

哈希表增加元素
在这里插入图片描述
增加元素注意两点:

  • 往后遍历寻找空闲位置是环形遍历,否则访问会数组越界
  • 发生哈希冲突找空闲位置的时候,有两种情况:这个位置一直是空的没放过元素;这个位置是空的,以前放过元素后来被删除了。

哈希表查询:
在这里插入图片描述
在线性探测写代码要注意:
在这里插入图片描述
当我们在去找value的时候,先计算哈希值发现它应该放在下标3的位置,取出这个位置的元素却不等于value,说明但是放value的时候发生哈希冲突了,访问4的时候发现位置是空的,

  • 如果这个位置一直是空的,没放过元素。此时不需要再往后找value了。因为如果这个位置一直是空的,那当时value要放的话肯定就放在这里了。
  • 如果这个位置是空的,以前放过元素,但后来被删除了。此时需要继续往后搜索。因为但是放value的时候,有可能这个位置元素还在,所以value往后找了个位置放了。

哈希表删除操作
在这里插入图片描述
我们在删除桶里面的元素并没有真的删除,只是把桶的状态改变了。

哈希表线性探测法代码实现

#include<iostream>
using namespace std;

enum State
{
    
    
	STATE_UNUSE,//从未使用过的桶
	STATE_USING,//正在使用的桶
	STATE_DEL,//元素被删除的桶
};
class Bucket
{
    
    
public:
	Bucket(int key=0,State state=STATE_UNUSE)
		:_key(key),_state(state){
    
    }
	int _key;//存储数据
	State _state;//存储状态
};
class HashTable
{
    
    
private:
	Bucket* _table;//动态开辟的哈希表
	int _tableSize;//桶的大小
	int _useBucketNum;//正在使用的桶个数
	double _loadFactor;//装载因子
	//在C++11以后,静态常量的整型类型在类里面可以直接初始化
	static const int _primeSize = 10;//素数大小
	static int _primes[_primeSize];//素数表
	int _primeIdx;//当前使用的素数下标
	void expand()
	{
    
    
		++_primeIdx;
		if (_primeIdx == _primeSize)
		{
    
    
			throw "hashtable is too large,can not expand anymore";
		}
		Bucket* newTable = new Bucket[_primes[_primeIdx]];
		for (int i = 0; i < _tableSize; i++)
		{
    
    
			if (_table[i]._state == STATE_USING)
			{
    
    
				int idx = _table[i]._key % _primes[_primeIdx];
				int k = idx;
				do
				{
    
    
					if (newTable[k]._state == STATE_UNUSE)
					{
    
    
						newTable[k]._key = _table[i]._key;
						newTable[k]._state = STATE_USING;
						break;
					}
					k = (k + 1) % _primes[_primeIdx];
				} while (k != idx);
			}
		}
		delete[]_table;
		_table = newTable;
		_tableSize = _primes[_primeIdx];
	}
public:
	HashTable(int size = _primes[0], double loadFactor = 0.75)
		:_useBucketNum(0), _loadFactor(loadFactor), _primeIdx(0)
	{
    
    
		//把用户传入的size调整到最近的比较大的素数上
		if (size != _primes[0])
		{
    
    
			for (; _primeIdx < _primeSize; _primeIdx++)
			{
    
    
				if (_primes[_primeIdx] > size)
				{
    
    
					break;
				}
			}
			//用户传入的size过大已经超过了最后一个数,调整为最后一个数
			if(_primeIdx == _primeSize)
				_primeIdx--;
		}
		_tableSize = _primes[_primeIdx];
		_table = new Bucket[_tableSize];
	}
	~HashTable()
	{
    
    
		delete[]_table;
		_table = nullptr;
	}
	bool insert(int key)
	{
    
    
		//考虑扩容
		double factor = _useBucketNum * 1.0 / _tableSize;
		if (factor > 0.75)
		{
    
    
			expand();
		}
		int idx = key % _tableSize;
		int i = idx;
		do
		{
    
    
			if (_table[i]._state == STATE_UNUSE)
			{
    
    
				_table[i]._key = key;
				_table[i]._state = STATE_USING;
				_useBucketNum++;
				return true;
			}
			i = (i + 1) % _tableSize;
		} while (i != idx);
	}
	bool erase(int key)
	{
    
    
		int idx = key % _tableSize;
		int i = idx;
		do
		{
    
    
			if (_table[i]._state == STATE_USING && _table[i]._key == key)
			{
    
    
				_table[i]._state = STATE_DEL;
				_useBucketNum--;
				break;
			}
			i = (i + 1) % _tableSize;
		} while (_table[i]._state != STATE_UNUSE && i != idx);
		return true;
	}
	bool find(int key)
	{
    
    
		int idx = key % _tableSize;
		int i = idx;
		do
		{
    
    
			if (_table[i]._key == key && _table[i]._state == STATE_USING)
			{
    
    
				return true;
			}
			i = (i + 1) % _tableSize;
		} while (_table[i]._state != STATE_UNUSE && i != idx);
		return false;
	}
};
int HashTable::_primes[_primeSize] = {
    
     3,7,23,47,97,251,443,911,1471,42773 };

int main()
{
    
    
	HashTable htable;
	htable.insert(12);
	htable.insert(24);
	htable.insert(38);
	htable.insert(15);
	htable.insert(14);
	cout << htable.find(12) << endl;
	htable.erase(12);
	cout << htable.find(12) << endl;
}

猜你喜欢

转载自blog.csdn.net/qq_41721746/article/details/124933949