哈希表,又称散列表,是一种根据关键字(key)而直接访问在内存存储位置的数据结构。它通过一个关键值的函数将所需的数据映射到表中的位置来访问数据,这个映射函数叫做散列函数,存放记录的数组叫做散列表。
构造哈希表的几种方法:
1. 直接定址法——取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A、B为常数。
2. 除留余数法——取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址。Hash(Key)= Key % m。
3. 平方取中法
4. 折叠法
5. 随机数法
6. 数学分析法
我们通常用除留余数法来构造哈希表。
哈希冲突 ,不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址的情况。任意的散列函数都不能避免产生冲突。
处理哈希冲突的闭散列方法-开放定址法
1. 线性探测
2. 二次探测
完整的源代码及测试用例如下:
enum State
{
EMPTY,
EXIST,
DELETE
};
template <class K>
struct __HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
//特化
template <>
struct __HashFunc<string>
{
static size_t BKDRHash(const char* str)
{
unsigned int seed = 131;
unsigned int hash = 0;
while(*str)
{
hash = hash * seed + (*str++);
}
return(hash & 0x7FFFFFFF);
}
size_t operator()(const string& key)
{
return BKDRHash(key.c_str());
}
};
template <class K, class V>
struct HashNode
{
pair<K, V> _kv;
State _s;
};
template <class K, class V>
class HashTable
{
public:
typedef HashNode<K, V> Node;
HashTable()
:_size(0)
{}
HashTable(size_t n)
:_size(0)
{
_table.resize(n);
}
bool Insert(const pair<K, V>& kv)
{
_check();
size_t index = _HashFunc(kv.first);
while(_table[index]._s == EXIST)
{
if(_table[index]._kv.first == kv.first)
{
return false;
}
++index; //线性探测
if(index == _table.size())
{
index = 0;
}
}
_table[index]._kv = kv;
_table[index]._s = EXIST;
++_size;
return true;
}
bool Remove(const K& key)
{
Node* node = Find(key);
if(node)
{
node->_s = DELETE;
--_size;
return true;
}
else
{
return false;
}
}
Node* Find(const K& key)
{
size_t index = _HashFunc(key);
while(_table[index]._s != EMPTY)
{
if(_table[index]._kv.first == key)
{
if(_table[index]._s == EXIST)
{
return &_table[index];
}
else
{
return NULL;
}
}
++index;
if(index == _table.size())
{
index = 0;
}
}
return NULL;
}
V& operator[](const K& key)
{
pair<Node*, bool> ret = Insert(make_pair(key, V()));
return (ret.first)._kv.second;
}
void Print()
{
for(size_t i = 0; i < _table.size(); ++i)
{
if(_table[i]._s == EXIST)
{
cout<<_table[i]._kv.first<<" ";
}
}
cout<<endl;
}
protected:
void _check()
{
if(_table.size() == 0)
{
_table.resize(11);
}
if((_size * 10) / _table.size() == 7)
{
size_t newSize = _table.size() * 2;
HashTable<K, V> newHT(newSize);
for(size_t i = 0; i < _table.size(); ++i)
{
if(_table[i]._s == EXIST)
{
newHT.Insert(_table[i]._kv);
}
}
Swap(newHT);
}
}
void Swap(HashTable<K, V>& ht)
{
swap(_size, ht._size);
_table.swap(ht._table);
}
size_t _HashFunc(const K& key)
{
return key % _table.size();
}
protected:
vector<Node> _table;
size_t _size; //哈希实际的数据个数
};
void TestHashTable()
{
int a[] = {89, 18, 49, 58, 9};
int len = sizeof(a) / sizeof(a[0]);
HashTable<int, int> ht;
for(int i = 0; i < len; ++i)
{
ht.Insert(make_pair(a[i], i));
}
ht.Print();
}