哈希表

Posted

tags:

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

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

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


  1. 直接定址法--取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A、B为常数。

  2. 除留余数法--取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址。Hash(Key)= Key % P。

  3. 平方取中法

  4. 折叠法

  5. 随机数法

  6. 数学分析法


1.线性探测

#include<iostream>

using namespace std;

enum State
{
	EMPTY,
	DELETE,
	EXITS,
};
template<class T>
class HashTable
{
public:
	HashTable(size_t capacity = 10)
		: _capacity(capacity)
		,_tables(new T[_capacity])
		, _states(new State[_capacity])
		, _size(0)
		
	{
		//将状态表置空
		for (size_t i = 0; i < _capacity; i++)
		{
			_states[i] = EMPTY;

		}
		//注意:不能用memset,因为这个函数是“置位”的,它将每一位置成设置的值
	}
	HashTable(const HashTable<T>&h)
		:_tables(new T[h._capacity])
		, _states(new State[h._capacity])
		, _size(h._size)
		, _capacity(h._capacity)
	{
		for (size_t i = 0; i < _capacity; i++)
		{
			_tables[i] = h._tables[i];
			_states[i] = h._states[i];
		}
	}
	HashTable<T>&operator=(HashTable<T> h)
	{
		if (this != &h)
		{
			swap(_tables, h._tables);
			swap(_states, h._states);
			swap(_size, h._size);
			swap(_capacity, h._capacity);
		}
		return *this;
	}
	~HashTable()
	{
		if (_tables != NULL)
		{
			delete[] _tables;
			_tables = NULL;
		}
		if (_states != NULL)
		{
			delete[] _states;
			_states = NULL;
		}
		
	}
public:
	bool Insert(const T&key)//插入
	{
		if (_size == _capacity)
		{
			cout << "hashtable is full";
			return false;
		}
		size_t index = _HashFunc(key);
		//线性探测
		while (_states[index] ==EXITS)
		{
			if (_tables[index] == key)
			{
				return false;
			}
			++index;
			if (index == _capacity)//若找到尾还未找到空位则从表头继续找
			{
				index = 0;
			}
		}
		_tables[index] = key;
		_states[index] = EXITS;
		_size++;
		
	}
	bool Find(const T&key)//查找
	{
		size_t index = _HashFunc(key);
		size_t start = index;//保存起始位置,若从这个位置找了一圈还没找到则元素不存在
		while (_tables[index] != EMPTY)
		{
			if (_tables[index] == key)
			{
				if (_states[index] != DELETE)
					return true;
				else
				{
					cout << "fail";
					return false;
				}
			}
			++index;
			if (index == _capacity)
				index = 0;//找到尾还未找到则从头继续找
			if (index == start)
			{
				cout << "fail";
				return false;
			}
		}
		cout << "fail";
		return false;
		
	}
	bool Remove(const T&key)
	{
		size_t index = _HashFunc(key);
		size_t start = index;

		while (_states[index] != EMPTY)
		{
			if (_tables[index] == key)
			{
				_states[index]=DELETE;
				_size--;
				return true;
			}
			++index;
			if (index == _capacity)
				index = 0;
			if (index == start)
				return false;
		}
		return false;
	}
	void Print()
	{
		if (_tables == NULL || _states == NULL)
			cout << "EMPTY";
		for (size_t i = 0; i < _capacity; i++)
		{
			printf("(%d-%d:%d) ",i, _states[i], _tables[i]);
		}
		cout << endl;
	}
private:
	size_t _HashFunc(const T&key)//安排在哈希表中的位置
	{
		return key%_capacity;
	}
private:
	size_t _capacity;//容量
	T* _tables;//哈希表
	State* _states;//状态表
	size_t _size;//存储元素个数
	
};

哈希冲突:

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

    散列表的荷载因子:α=填入表的元素个数/散列表长度

    填入表的元素个数越多,产生冲突的可能性越大,反之,越小

    荷载因子应严格限制在0.7~0.8以下,超过0.8则会导致cpu的缓存不命中率上升

故以下方法为检查容量,若荷载因子过大则进行扩容

#include<iostream>

using namespace std;

enum State
{
	EMPTY,
	DELETE,
	EXITS,
};
template<class T>
class HashTable
{
public:
	HashTable(size_t capacity = 10)
		: _capacity(capacity)
		,_tables(new T[_capacity])
		, _states(new State[_capacity])
		, _size(0)
		
	{
		//将状态表置空
		for (size_t i = 0; i < _capacity; i++)
		{
			_states[i] = EMPTY;

		}
		//注意:不能用memset,因为这个函数是“置位”的,它将每一位置成设置的值
	}
	HashTable(const HashTable<T>&h)
		:_tables(new T[h._capacity])
		, _states(new State[h._capacity])
		, _size(h._size)
		, _capacity(h._capacity)
	{
		for (size_t i = 0; i < _capacity; i++)
		{
			_tables[i] = h._tables[i];
			_states[i] = h._states[i];
		}
	}
	HashTable<T>&operator=(HashTable<T> h)
	{
		if (this != &h)
		{
			swap(_tables, h._tables);
			swap(_states, h._states);
			swap(_size, h._size);
			swap(_capacity, h._capacity);
		}
		return *this;
	}
	~HashTable()
	{
		if (_tables != NULL)
		{
			delete[] _tables;
			_tables = NULL;
		}
		if (_states != NULL)
		{
			delete[] _states;
			_states = NULL;
		}
		
	}
public:
	bool Insert(const T&key)//插入
	{
		/*if (_size == _capacity)
		{
			cout << "hashtable is full";
			return false;
		}*/
		Checkcapacity();
		size_t index = _HashFunc(key);
		
		//线性探测
		while (_states[index] ==EXITS)
		{
			if (_tables[index] == key)
			{
				return false;
			}
			++index;
			if (index == _capacity)//若找到尾还未找到空位则从表头继续找
			{
				index = 0;
			}
		}
		_tables[index] = key;
		_states[index] = EXITS;
		_size++;
		
	}
	bool Find(const T&key)//查找
	{
		size_t index = _HashFunc(key);
		size_t start = index;//保存起始位置,若从这个位置找了一圈还没找到则元素不存在
		while (_tables[index] != EMPTY)
		{
			if (_tables[index] == key)
			{
				if (_states[index] != DELETE)
					return true;
				else
				{
					cout << "fail";
					return false;
				}
			}
			++index;
			if (index == _capacity)
				index = 0;//找到尾还未找到则从头继续找
			if (index == start)
			{
				cout << "fail";
				return false;
			}
		}
		cout << "fail";
		return false;
		
	}
	bool Remove(const T&key)
	{
		size_t index = _HashFunc(key);
		size_t start = index;

		while (_states[index] != EMPTY)
		{
			if (_tables[index] == key)
			{
				_states[index]=DELETE;
				_size--;
				return true;
			}
			++index;
			if (index == _capacity)
				index = 0;
			if (index == start)
				return false;
		}
		return false;
	}
	void Print()
	{
		if (_tables == NULL || _states == NULL)
			cout << "EMPTY";
		for (size_t i = 0; i < _capacity; i++)
		{
			printf("(%d-%d:%d) ",i, _states[i], _tables[i]);
		}
		cout << endl;
	}
private:
	void Checkcapacity()
	{
		if (_size * 10 / _capacity == 7)
		{
			HashTable<T>tmp(2 * _capacity);
			for (size_t i = 0; i < _capacity; i++)
			{
				if (_states[i] == EXITS)
				{
					tmp.Insert(_tables[i]);
				}
			}
			this->_swap(tmp);
		}
		
	}
	void _swap(HashTable<T>&h)
	{
		swap(_tables, h._tables);
		swap(_states, h._states);
		swap(_capacity, h._capacity);
		swap(_size, h._size);
	}
	size_t _HashFunc(const T&key)//安排在哈希表中的位置
	{
		return key%_capacity;
	}
private:
	size_t _capacity;//容量
	T* _tables;//哈希表
	State* _states;//状态表
	size_t _size;//存储元素个数
	
};



技术分享未完待续

本文出自 “无以伦比的暖阳” 博客,请务必保留此出处http://10797127.blog.51cto.com/10787127/1776010

以上是关于哈希表的主要内容,如果未能解决你的问题,请参考以下文章

下文中的哈希片段指的是啥?

URL片段的最大长度(哈希)

URL的PHP​​和哈希/片段部分

从 URL 获取片段(哈希“#”后的值)[关闭]

带有哈希片段的锚未导航到匹配的 id

一致性哈希算法PHP测试片段