C++ 哈希表 线性探测 二次探测 哈希桶

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 哈希表 线性探测 二次探测 哈希桶相关的知识,希望对你有一定的参考价值。

#pragma once

#include<iostream>//含一次探测  二次探测
#include<vector>
#include<math.h>

using namespace std;

enum Status
{
	EXIST,
	EMPTY,
	DELET,
};

template <class K,class V> //key/value形式结构体
struct KV
{
	K _key;
	V _value;
	KV(const K& key = K(), const V& value = V())
		:_key(key)
		, _value(value)
	{}
};

template <class K, class V>
class HashTable
{
public:
	KV<K,V>* _tables;
	size_t _size;
	size_t _capacity;
	Status* _status;

public:
	HashTable()
		:_tables(NULL)
		,_size(0)
		, _capacity(0)
		, _status(NULL)
	{}
	void  Insert(const K& key , const V& value )
	{
		if (_capacity == 0 || _size * 10 / _capacity > 7)
		{
			if(!_IncreaseCapacity())
				cout<<"线性探测散列表已满"<<endl;
		}
			
		size_t i = _HashFanction1(key);
		do
		{
			
			if (key == _tables[i]._key&&_status[i]==EXIST)
					break;
			if (_status[i] != EXIST)
			{	
				_tables[i]._key = key;
				_tables[i]._value = value;
				_status[i] = EXIST;
				++_size;
				break;
			}
			else if (++i >= _capacity)
				i = 0;
		} while (1);
		
	}

	void  Insert2(const K& key, const V& value)
	{
		if (_capacity == 0 || _size * 10 / _capacity > 7)
		{
			if (!_IncreaseCapacity())
				cout << "线性探测散列表已满" << endl;
		}
		int count = 0;//二次探测的计数器
		size_t i = _HashFanction2(key,count);
		do
		{
			if (i<0)
				i = _capacity + i;
			if (key == _tables[i]._key&&_status[i] == EXIST)
				break;
			if (_status[i] != EXIST)
			{
				_tables[i]._key = key;
				_tables[i]._value = value;
				_status[i] = EXIST;
				++_size;
				break;
			}
			else 
				i = _HashFanction2(key, i);
		} while (1);

	}

	int Find(const K& key)
	{
		size_t i = _HashFanction1(key);
		size_t j = i;
		do
		{
			
			if (_status[i] == EXIST&&key==_tables[i]._key)
			{
				
				return i;
			}
			else if (++i >= _capacity)
				i = 0;
		} while (i!=j);
		return -1;

	}

	void Remove(const K& key)
	{
		size_t i = _HashFanction1(key);
		size_t j = i;
		do
		{

			if (_status[i] == EXIST&&key == _tables[i]._key)
			{
				_status[i] = DELET;
				break;
			}
			else if (++i >= _capacity)
				i = 0;
		} while (i != j);
	}
	
	void print()
	{
		size_t i = 0;
		for (; i < _capacity; ++i)
		{
			printf("[%d] K: %d  V: %d S: %d \n",i, _tables[i]._key, _tables[i]._value, _status[i]);
		}
	}
	
protected:
	size_t _HashFanction1(const K& key)//一次探测 (线性探测)
	{

		return key%_capacity;
	}

	int _HashFanction2(const K& key,const int i)//二次次探测 (防止数据积累在一块内存)
	{

		return (key+(int)pow(-1,i)*i*i)%_capacity;
	}

	bool _IncreaseCapacity()
	{
		const int _PrimeSize = 28;//素数表
		static const unsigned long _PrimeList[_PrimeSize] =
		{
			53ul, 97ul, 193ul, 389ul, 769ul,
			1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
			49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
			1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
			50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
			1610612741ul, 3221225473ul, 4294967291ul
		};
		for (int i = 0; i < _PrimeSize; ++i)
		{
			if (_PrimeList[i]>_capacity)
			{
				size_t newCapacity = _PrimeList[i];
				HashTable<K, V> newHash;
				newHash._tables = new KV<K,V>[newCapacity];
				newHash._status = new Status[newCapacity];
				newHash._capacity=_PrimeList[i];
				for (size_t j = 0; j < newCapacity; ++j)
				{
					if (_status&&j<_capacity&&_status[j] == EXIST)
					{
						//newHash.Insert(_tables[j]._key, _tables[j]._value);//一次探测的增容调一次探测的插入函数
						newHash.Insert2(_tables[j]._key, _tables[j]._value);//二次探测。。。。。。
					}
					else
					{
						newHash._status[j] = EMPTY;
						newHash._tables[j]._key = 0;
						newHash._tables[j]._value = 0;
					}
						
				}
				swap(_tables, newHash._tables);
				swap(newHash._status,_status);
				swap(newHash._capacity, _capacity);


				return true;
			}
		}
		return false;

	}

};

#pragma once

#include<iostream>//哈希桶
#include<vector>
#include<math.h>
#include<string>

using namespace std;

template <class K>
class GetKey
{
public:
	size_t operator()(const K& key)
	{
		return key;
	}
};

static size_t BKDRHash(const char * str)
{
	unsigned int seed = 131; // 31 131 1313 13131 131313
	unsigned int hash = 0;
	while (*str)
	{
		hash = hash * seed + (*str++);
	}
	return (hash & 0x7FFFFFFF);
}

template <>
class GetKey<string>
{
public:
	size_t operator()(const string & key)
	{
		return BKDRHash(key.c_str());
	}
};
template <class K,class V> //key/value形式结构体
struct KeyValue
{
	K _key;
	V _value;
	KeyValue<K, V>* _next;
	KeyValue(const K& key = K(), const V& value = V())
		:_key(key)
		, _value(value)
		, _next(NULL)
	{}
};

template <class K, class V>
class HashBucket
{
public:
	vector<KeyValue<K, V>*> _tables;
	size_t _size;

public:
	HashBucket()
		:_size(0)
	{}
	void  Insert(const K& key , const V& value )
	{
		if (_tables.capacity()==0|| _size * 10 / _tables.capacity() > 7)
		{
			if(!_IncreaseCapacity())
				cout<<"线性探测散列表已满"<<endl;
		}
			
		size_t i = _HashFanction1(key);
		KeyValue<K, V>* cur = _tables[i];
		if (cur == NULL)
			_tables[i] = new KeyValue<K, V>(key, value);
		else
		{
			while (cur)
			{

				if (cur->_key == key)
					return;
				else if (cur->_next == NULL)
					break;
				else
					cur = cur->_next;
			}
			cur->_next = new KeyValue<K, V>(key, value);
		}
		++_size;
	}

	int Find(const K& key)
	{
		size_t i = _HashFanction1(key);
		KeyValue<K, V>* cur = _tables[i];
		while (cur)
		{
			if (cur->_key == key)
				return i;
			cur = cur->_next;
		}
		return -1;

	}

	void Remove(const K& key)
	{
		size_t i = _HashFanction1(key);
		KeyValue<K, V> * cur =_tables[i];
		KeyValue<K, V> * prev = NULL;

		while (cur)
		{
			if (cur->_key == key)
			{
				if (prev)
				{
					prev->_next = cur->_next;
				}
				else
					_tables[i] = NULL;
					delete cur;
					return;
			}
			prev = cur;
			cur = cur->_next;
			
		}
	}
	
	void print()
	{
		size_t i = 0;
		for (; i < _tables.capacity(); ++i)
		{
			KeyValue<K, V>* cur = _tables[i];
			
			if (cur == NULL)
				//printf("[%d]:K= %d V= %d ->", i, -1,-1);
				cout<< "[" << i << "] "<< -1 << " " << -1 << " " << "->";
			while (cur)
			{
				
				//printf("[%d]:K= %d V= %d ", i, cur->_key,cur->_value);
				cout << "[" << i << "] "<< _tables[i]->_key << " " << _tables[i]->_value << " " << "->";

				cout << "->";
				cur = cur->_next;
			}
			cout <<" NULL"<<endl;
		}

	}
	
protected:
	size_t _GetKey(const K& key)
	{
		return GetKey<K>()(key);
	}
	size_t _HashFanction1(const K& key)//一次探测 (线性探测)
	{
		size_t k = _GetKey(key);
		return k%_tables.capacity();
	}

	bool _IncreaseCapacity()
	{
		const int _PrimeSize = 28;
		static const unsigned long _PrimeList[_PrimeSize] =
		{
			53ul, 97ul, 193ul, 389ul, 769ul,
			1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
			49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
			1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
			50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
			1610612741ul, 3221225473ul, 4294967291ul
		};
		for (int i = 0; i < _PrimeSize; ++i)
		{
			if (_PrimeList[i]>_tables.size())
			{
				size_t newCapacity = _PrimeList[i];
				vector<KeyValue<K, V>*> newtables;
				newtables.resize(newCapacity, 0);
				for (size_t j = 0; j < _tables.capacity(); ++j)
				{
					KeyValue<K, V>* cur = _tables[j];
					while (cur)
					{
						size_t k = _HashFanction1(cur->_key);
						
						KeyValue<K, V>* tmp = cur;
						KeyValue<K, V>* tmp2 = newtables[k];
						if (tmp2 = NULL)
						{
							newtables[i] = cur;
							break;
						}
						while (tmp2->_next)
						{	
							tmp2->_next = cur;
						}
						tmp->_next = cur;
						cur->_next = NULL;
						  _tables[j] = tmp;
					   cur = tmp;
					}
					
				}
				swap(newtables, _tables);
			}
			return true;
		}
	return false;

}

};

#include"hashtable.hpp" //测试用例
#include"hashbucket.hpp"

using namespace std;

void test()
{

	HashTable<int, int> h1;
	
	for (int i = 0; i <30;++i)
		h1.Insert(i, i);
	h1.Insert(100,1);
	h1.Insert(170, 3);
	h1.Insert(223, 5);
	h1.Insert(56, 7);
	h1.Insert(550,9);
	h1.print();
	cout<<h1.Find(223)<<endl;
	cout << h1.Find(224) << endl;
	h1.Remove(56);
	h1.Remove(58);

	h1.print();

}

void test2()
{

	HashTable<int, int> h1;

	for (int i = 0; i < 30;++i)
	h1.Insert(i, i);
	h1.Insert2(100, 1);
	h1.Insert2(170, 3);
	h1.Insert2(223, 5);
	h1.Insert2(56, 7);
	h1.Insert2(550, 9);
	h1.print();
	cout << h1.Find(223) << endl;
	cout << h1.Find(224) << endl;
	h1.Remove(56);
	h1.Remove(58);

	h1.print();
}

void test3()
{
	HashBucket<int, int>  h1;
	h1.Insert(1,1);
	h1.Insert(3, 3);
	h1.Insert(5, 5);
	h1.Insert(7, 7);
	h1.Insert(54, 54);
	h1.Insert(107, 107);
	for (int i = 0; i < 99;i+=2)
		h1.Insert(i, i);

	h1.print();
	cout<<h1.Find(1)<<endl;
	cout<<h1.Find(107)<<endl;
	cout << h1.Find(5) << endl;

	h1.Remove(54);
	h1.print();


}
void test4()
{
	HashBucket<string, string>  h1;
	h1.Insert("裴培华", "帅哥");
	h1.Insert("农文彤", "大屌");
	h1.Insert("鸭仔", "舎宝");
	h1.Insert("童坤坤", "学霸");
	h1.print();
	cout<<h1.Find("裴培华")<<endl;
	h1.Remove("农文彤");
	h1.print();


}

int main()
{
	//test();
	//test2();
	//test3();
	test4();
	return 0;
}


以上是关于C++ 哈希表 线性探测 二次探测 哈希桶的主要内容,如果未能解决你的问题,请参考以下文章

哈希表-线性探测插入删除

哈希表

哈希表解决冲突法(二次探测)

C++数据结构——哈希表

C++数据结构——哈希表

C++数据结构——哈希表