哈希表实现及解决冲突的方法
哈希表,哈希冲突2016-11-04
#pragma once
#include<vector>
using namespace std;
#include<cmath>
#include<cstring>
namespace HASHTABLE
{
enum Status{ EMPTY, DELETE, EXIST, };
template<typename K, typename V>
struct HashTableNode
{
K _key;
V _value;
Status _status;
HashTableNode(const K& key = K(), const V& value = V())
:_key(key)
, _value(value)
, _status(EMPTY)
{}
};
template<typename K>
struct __HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
template<> //由于string用的也比较多,所以将string实现成偏特化
struct __HashFunc<string>
{
size_t operator()(const string& str)
{
size_t num = 0;
int len =(int)str.size();
int i = 0;
while (len--)
{
num += str[i] * (int)pow(128.0, len);
i++;
}
return num;
}
};
//线性探测 //二次探测
template<typename K, typename V,class HashFunc=__HashFunc<K>>
class HashTable
{
typedef HashTableNode<K, V> Node;
public:
HashTable()
:_size(0)
{
_table.resize(_GetPrime(0));
}
HashTable(const HashTable<K, V,HashFunc>& hash)
{
size_t newsize = hash._table.size(); //得到hash的大小
_table.resize(newsize); //先扩容
for (size_t i = 0; i <_table.size(); i++) //将hash表中的关键码拷贝到到新表中
{
if (hash._table[i]._status == EXIST)
{
_table[i]._key = hash._table[i]._key;
_table[i]._value = hash._table[i]._value;
_table[i]._status = EXIST;
}
}
_size = hash._size;
}
HashTable<K, V, HashFunc>& operator=(const HashTable<K, V, HashFunc>& hash)
{
if (this != &hash)
{
HashTable<K, V, HashFunc> h(hash);
Swap(h);
}
return *this;
}
Node* Find(const K& key)
{
int index = _HashFunc(key);
if (index >= 0)
{
int start = index; //记录第一次计算的位置
while (_table[index]._status != EMPTY) //这个位置要不为空
{
if (_table[index]._key == key)
{
//如果已经找到这个关键码,还要判断这个关键码的状态
if (_table[index]._status == EXIST)
return &_table[index];
}
index++;
if (index == _table.size())
index = 0;
if (index == start) //如果此时表中都不为空,但是有标记删除的,所以还有可能再找到起始位置
break; //这种情况是找不到的
}
}
return NULL;
}
bool Insert(const K& key, const V& value)
{
_CheckCapacity(); //先判断需不需要增加表的长度
int index = _HashFunc(key);
if (index >= 0) //如果已经找到了在hash中映射的地址
{
while (_table[index]._status == EXIST) //先找到这个不为存在的位置,由于负载因子的存在,所以不可能全都是EXIST
{
index++; //线性探测可以改为二次探测,双散列也可以
if (index == _table.size())
index = 0;
}
//如果这个位置不是存在的状态,再插入
_table[index]._key = key;
_table[index]._value = value;
_table[index]._status = EXIST;
_size++;
return true;
}
return false;
}
bool Remove(const K& key)
{
//要删除之前先要找到这个要删除的关键码
Node* del = Find(key);
if (del) //如果已经找到了要删除的关键码,则采用懒惰删除
{
del->_status = DELETE;
_size--; //元素的个数要减一
return true;
}
return false;
}
void Swap(HashTable<K, V, HashFunc>& table)
{
if (this != &table) //不是自己与自己交换
{
_table.swap(table._table);
swap(_size, table._size);
}
}
protected:
int _HashFunc(const K& key)
{
if (_table.size())
{ //生成一个匿名对象,调用仿函数
return HashFunc()(key)%_table.size();
}
return -1;
}
static unsigned _GetPrime(const unsigned long size)
{
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 (size_t i = 0; i <_PrimeSize; i++) //返回一个比当前hash表大的素数
{
if (size < _PrimeList[i])
return _PrimeList[i];
}
return _PrimeList[_PrimeSize - 1]; //否则返回最后一个值
}
void _CheckCapacity() //如果载荷因子大于0.8,则这时候插入的效率就很低,所以这时候就要增大表的大小
{
//载荷因子等于元素的个数除以表的长度
if (_table.size() == 0 || _size * 10 / _table.size() >= 8) //这时候插入的效率很低,就要增加hash表的长度
{
//由于hash表已经扩容,所以要重新计算表中元素的哈希地址
HashTable<K, V, HashFunc> hash; //先创建一个临时的表
size_t newsize = _GetPrime(_table.size());
hash._table.resize(newsize);
for (size_t i = 0; i <_table.size(); i++) //将旧的表中的关键码拷贝到hash中
{
if (_table[i]._status == EXIST)
{
hash.Insert(_table[i]._key, _table[i]._value);
}
}
//交换两个hash表
Swap(hash);
}
}
private:
vector<Node> _table;
size_t _size;
};
}
namespace HashTable_link
{
template<typename K,typename V>
struct HashTableNode
{
K _key;
V _value;
HashTableNode<K, V>* _next;
HashTableNode(const K& key=K(),const V& value=V())
:_key(key)
, _value(value)
, _next(NULL)
{}
};
template<class K> //为了将得到hash地址统一起来,使用仿函数,将整型的时候默认实现出来
struct __HashFunc //仿函数,将关键值转换成整型数值
{
size_t operator()(const K& key)
{
return key;
}
};
//由于string也是常用的类型,所以对string进行偏特化
template<>
struct __HashFunc<string>
{
size_t operator()(const string& str)
{
size_t num = 0;
for (int i = 0; i < (int)str.size(); i++)
{
num += num * 131 +str[i];
}
return num;
}
};
template<typename K,typename V,class HashFunc=__HashFunc<K>> //仿函数默认类型是K
class HashTable
{
typedef HashTableNode<K, V> Node;
public:
HashTable()
:_size(0)
{
_tables.resize(_GetPrime(0));
}
HashTable(const HashTable<K, V,HashFunc>& hash)
{
_tables.resize(hash._tables.size());
for (int i = 0; i <(int)hash._tables.size(); i++) //将当前表的内容导入到新表
{
Node* cur = hash._tables[i];
while (cur)
{
Insert(cur->_key, cur->_value);
cur = cur->_next;
}
}
}
HashTable<K, V, HashFunc>& operator=(const HashTable<K, V, HashFunc>& hash)
{
if (this != &hash) //如果不是自赋值
{
HashTable<K, V, HashFunc> tmp(hash);
Swap(tmp);
}
return *this;
}
~HashTable()
{
for (int i = 0; i <(int)_tables.size(); i++) //将当前表的内容导入到新表
{
Node* cur =_tables[i];
Node* del = NULL;
while (cur)
{
del = cur;
cur = cur->_next;
delete del;
}
}
}
Node* Find(const K& key)
{
int index = _HashFunc(key);
if (index >= 0)
{
Node* cur = _tables[index];
while (cur)
{
if (cur->_key == key)
{
return cur;
}
cur = cur->_next;
}
}
return NULL;
}
bool Insert(const K& key,const V& value)
{
_CheckSize(); //先判断表的载荷因子是否已经达到1,达到1的话就扩容
Node* ret = Find(key);
if (ret== NULL) //如果要插入的key不存在的,则可以插入
{
int index = _HashFunc(key);
Node* cur = new Node(key,value);
cur->_next = _tables[index];
_tables[index] = cur;
_size++;
return true;
}
return false;
}
bool Remove(const K& key)
{
int index = _HashFunc(key);
if (index >= 0)
{
Node* prev = NULL;
Node* cur = _tables[index];
while (cur)
{
if (cur->_key ==key)
{
if (prev == NULL)
{
_tables[index] = cur->_next; //删除第一个结点
}
else
{
prev->_next = cur->_next;
}
delete cur;
_size--;
return true;
}
prev = cur;
cur = cur->_next;
}
}
return false;
}
void Swap(HashTable<K, V, HashFunc>& hash)
{
_tables.swap(hash._tables);
swap(_size,hash._size);
}
protected:
static unsigned _GetPrime(const unsigned long size)
{
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 (size_t i = 0; i <_PrimeSize; i++) //返回一个比当前hash表大的素数
{
if (size < _PrimeList[i])
return _PrimeList[i];
}
return _PrimeList[_PrimeSize - 1]; //否则返回最后一个值
}
void _CheckSize()
{
if (_tables.size()==0||_size/_tables.size() == 1) //如果表的长度为0,或者载荷因子为1,则先扩容
{
HashTable<K, V, HashFunc> hash; //创建一个临时的新hash表
hash._tables.resize(_GetPrime(_tables.size()));
for (int i = 0; i <(int)_tables.size(); i++) //将当前表的内容导入到新表
{
Node* cur = _tables[i];
while (cur)
{
hash.Insert(cur->_key,cur->_value);
cur = cur->_next;
}
}
Swap(hash); //交换两个表的内容
}
}
int _HashFunc(const K& key)
{
if (_tables.size())
{
return (HashFunc()(key))%_tables.size(); //先构造一个匿名对象,再调用仿函数
}
return -1;
}
private:
vector<Node*> _tables;
size_t _size;
};
}