哈希表(散列表)

哈希表,根據關鍵字(key)直接訪問在內存存儲位置的數據結構。

它通過一個關鍵值的函數將所需的數據映射到表中的位置來訪問數據,這個映射函數叫做散列函數,存放記錄的數組叫做散列表。

構造哈希表的幾種方法
直接定址法--取關鍵字的某個線性函數爲散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A、B爲常數。 

除留餘數法--取關鍵值被某個不大於散列表長m的數p除後的所得的餘數爲散列地址。Hash(Key)= Key % P。

哈希衝突/哈希碰撞不同的Key值經過哈希函數Hash(Key)處理以後可能產生相同的值哈希地址,我們稱這種情況爲哈希衝突。任意的散列函數都不能避免產生衝突。

散列表的載荷因子=填入表中的元素個數/散列表的長度



源代碼實現如下:
</pre><pre name="code" class="cpp">#pragma once

#include <iostream>
#include <string>

using namespace std;

template <class K,class V>
//節點的結構
struct HashTableNode
{
	K _key;//關鍵字
	V _value;//關鍵字對應的值

};

//狀態
enum Status
{
	EMPTY,   //空
	DELETE,  //刪除
	EXITS    //正常存在
};


//仿函數
template <typename K>
struct _HashFunc
{
	size_t operator()(const K& key)
	{
		return key;
	}
};

template<>
struct _HashFunc<string>
{
	size_t operator()(const string & key)
	{
		size_t ikey = 0;
		char * str = (char *)key.c_str();
		while (*str)
		{
			ikey += *str;
			*str++;
		}
		return ikey;
	}
};

//哈希表的二次探測
template <typename K,typename V>
class HashTable
{
	//重命名爲Node
	typedef HashTableNode<K, V> Node;

public:
	//構造
	HashTable(size_t capacity = 10)
		:_size(0)
		,_capacity(capacity)
		,_tables(new Node[capacity])
		,_status(new Status[capacity])
	{
		//_status初始化爲空
		for (size_t i = 0; i < _capacity; i++)
		{
			_status[i] = EMPTY;
		}
	}
	//析構函數
	~HashTable()
	{
		if (_tables)
		{
			delete[]_tables;
		}
		if (_status)
		{
			delete[]_status;
		}
	}

public:
	//插入
	bool Insert(const K& key, const V& value)
	{
		//是否需要擴容
		_CheckCapacity();
		//哈希地址
		size_t index = HashFunc(key);
		size_t start = index;

		//二次檢測
		size_t i = 1;
		//如果該地址處存在數據
		while (_status[index] == EXITS)
		{
			//該數據已經存在
			if (_tables[index]._key == key)
			{
				return false;
			}

			//二次探測
			index = start + i*i;
			index %= _capacity;
			i++;
		}
		_tables[index]._key = key;
		_tables[index]._value = value;
		_status[index] = EXITS;
		_size++;
		return true;
	}

	//刪除
	bool Remove(const K& key)
	{
		//哈希地址
		size_t index = HashFunc(key);
		size_t start = index;
		size_t i = 1;
		
		while (_status[index] == EXITS)
		{
			//該數據存在
			if (_tables[index]._key == key)
			{
				_status[index] = DELETE;
				return true;
			}
			//數據不再當前位置
			index = start + i*i;
			index %= _capacity;
			i++;
			if (index == start)
			{
				return false;
			}
		}
		return false;
	}

	//查找
	Node * Find(const K & key)
	{
		size_t index = HashFunc(key);
		size_t start = index;
		size_t i = 1;

		while (_status[index] == EXITS)
		{
			//該數據存在
			if (_tables[index]._key == key)
			{
				return &_tables[index];
			}
			//數據不再當前位置
			index = start + i*i;
			index %= _capacity;
			i++;
			if (index == start)
			{
				return NULL;
			}
		}
		return NULL;
	}

	//打印
	void Print()
	{
		cout << "0表示(空);1表示(刪除);2表示(正常)" << endl;
		for (size_t i = 0; i < _capacity; i++)
		{
			cout << "{" << _status[i] << "," << _tables[i]._key << ","
				<< _tables[i]._value << "}" << "->";
		}
		cout << endl;
	}


protected:
	//是否擴容
	void _CheckCapacity()
	{
		//載荷因子大於等於0.7時擴容
		if (_size * 10 % _capacity >= 7)
		{
			HashTable<K, V> tmp(2 * _capacity);//新的容積
			for (size_t i = 0; i < _capacity; i++)
			{
				//如果數據正常
				if (_status[i] == EXITS)
				{
					//插入到新的哈希表中
					tmp.Insert(_tables[i]._key, _tables[i]._value);
				}
			}
			Swap(tmp);
		}
	}
	//交換
	void Swap(HashTable<K, V> & tmp)
	{
		swap(_tables, tmp._tables);
		swap(_status, tmp._status);
		swap(_size, tmp._size);
		swap(_capacity, tmp._capacity);
	}
	//計算哈希地址(除留取餘法)
	size_t HashFunc(const K & key)
	{
		_HashFunc<K> hf;
		return hf(key) % _capacity;
	}

private:
	Node * _tables;//哈希表
	Status* _status;//狀態
	size_t _size;//存儲數據的大小
	size_t _capacity;//容量
};






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章