线性表,二叉搜索树、AVL树、红黑树B树中,元素在存储结构中的位置与元素的关键码之间不存在直接的对应关系。在数据结构中搜索一个元素需要进行一系列的关键码比较。搜索的效率取决于搜索过程中比较的次数。
理想的搜索方法是可以不经过任何比较,一次直接从表中得到要搜索的元素。
如果构造一种存储结构,使元素的存储位置与它的关键码之间建立一个确定的对应函数关系Hash(),那么每个元素关键码与结构中的一个唯一的存储位置相对应:
Address = Hash(Key)
在插入时,根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放。在搜索时,对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功。该方式即散列方法(Hash Method),在散列方法中使用的转换函数叫着散列函数(Hash function),构造出来的结构叫散列表(Hash Table)。
用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快。
哈希冲突(哈希碰撞)
对于两个数据元素的关键字Ki和Kj(i != j),有Ki != Kj(i != j),但HashFun(Ki)== HashFun(Kj),将该种现象称为哈希冲突或哈希碰撞。把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”,由同义词引起的冲突称为同义词冲突。
在哈希表中,哈希冲突越多就越不稳定。
散列冲突处理方法
任何一种散列函数也不能避免产生冲突,因此选择好的解决冲突溢出的方法十分重要。为了减少冲突必须对散列表加以改造。
闭散列法
闭散列也叫开地址法。设散列表的编址为0到m-1,当添加关键码key时通过散列函数hash(key)计算key的存放位置,但在存放时发现这个桶已经被另一个keyx占据了,即发生哈希冲突。如果表未被装满,表示在给定的范围内必然还有空位置,则可以把key存放到表中“下一个”空位中。
简而言之:一旦发生冲突,就去寻找下一个空的散列表地址,只要散列表足够大,空的散列地址总能找到。
下面是我实现的线性探测和二次探测的代码:#pragma once
#include<vector>
#include<iostream>
#include<string>
namespace OPEN
{
using namespace std;
enum State
{
EXIST, Delete, EMPTY
};
template<class K, class V >
struct HashNode
{
pair<K, V> _kv;
State _state;//标记一个位置的状态
HashNode()
:_state(EMPTY)
{}
};
template<class K>
struct __HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
template<>
struct __HashFunc<string>
{
static size_t BRDRHash(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 BRDRHash(key.c_str());
}
};
/*
struct __HashFuncString
{
static size_t BRDRHash(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 BRDRHash(key.c_str());
}
};
*/
template<class K, class V, class HashFunc = __HashFunc<K>>
class HashTable
{
public:
HashTable()
:_n(0)
{}
//线性探测
bool Insert(pair<K, V>& kv)
{
CheckCapacity();
size_t index = _HashFunc(kv.first);
while (_tables[index]._state == EXIST)
{
if (_tables[index]._kv.first == kv.first)
{
return false;//检查冗余,表示这个地方已经有数据了
}
++index;
if (index = _tables.size())//走到了数组的最后,折回到数组的头重新往后
{
index = 0;
}
}
_tables[index]._kv = kv;
_tables[index]._state = EXIST;
++_n;
return true;
}
//二次探测
bool Insert2(pair<K, V>& kv)
{
CheckCapacity();
size_t i = 1;
size_t index = _HashFunc(kv.first);
while (_tables[index]._state == EXIST)
{
if (_tables[index]._kv.first == kv.first)
{
return false;//检查冗余,表示这个地方已经有数据了
}
index += i*i;
index = index % _tables.size();//走到了数组的最后,折回到数组的头重新往后
++i;
}
_tables[index]._kv = kv;
_tables[index]._state = EXIST;
++_n;
return true;
}
HashNode<K, V>* Find(const K& key)
{
size_t index = _HashFunc(key);
while (_tables[index]._state != EMPTY)
{
if (_tables[index]._kv.first == key)
{
if (_tables[index]._state == EXIST)
{
return &_tables[index];
}
}
++index;
if (index == _tables.size())
{
index = 0;
}
}
return NULL;
}
bool Remove(const K& key)
{
HashNode<K, V>* node = Find(key);
if (node)
{
node->_state = DELETE;
return true;
}
else
{
return false;
}
}
size_t Size()
{
return _n;
}
size_t Capacity()
{
return _tables.size();
}
/*
bool Insert2(pair<K, V>& kv)
{
size_t index = _HashFunc2(kv.first);
while (_tables[index]._state == EXIST)
{
++index;
if (index = _tables.size())
{
index = 0;
}
_tables[index]._kv = kv;
_tables[index]._states = EXIST;
++_n;
}
}
*/
private:
//pair<K, V>* _tables;//数组
//size_t _size;
//size_t _capacity;//增容
vector<HashNode<K, V>> _tables;
size_t _n;//实际存了多少个数
size_t GetNextPrime(size_t value)
{
/*const int _PrimeSize = 28;*/
/*static const unsigned long _PrimeList[_PrimeSize] =
{
53ul, 97ul, 193ul
};*/
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++)
{
if (_PrimeList[i]>value)
{
return _PrimeList[i];
}
}
return _PrimeList[_PrimeSize - 1];
}
void CheckCapacity()
{
if (_tables.empty())
{
_tables.resize(GetNextPrime(0));
return;
}
if (_n * 10 / _tables.size() == 7) //容量超过70%的时候容易发生哈希冲突,开始增容
{
size_t newsize = GetNextPrime(_tables.size());
HashTable<K, V, HashFunc> newHT;
newHT._tables.resize(newsize);
for (size_t i = 0; i < _tables.size(); ++i)
{
if (_tables[i]._state == EXIST)
{
newHT.Insert(_tables[i]._kv);
}
}
_tables.swap(newHT._tables);
}
}
size_t _HashFunc(const K& key)//作用???
{
HashFunc hash;
return hash(key) % _tables.size();
}
};
void Test()
{
HashTable<int, int> ht1;
ht1.Insert(make_pair(1, 0));
ht1.Insert(make_pair(2, 0));
ht1.Insert(make_pair(3, 0));
ht1.Insert(make_pair(4, 0));
HashTable<int, int> ht2(ht1);
for (int i = 0; i < 54; i++)
{
ht1.Insert(make_pair(i, i));
}
//HashTable<string, string,__HashFunc<string>> dict;
HashTable<string, string> dict;
dict.Insert(make_pair(string("left"), string("左边")));
dict.Insert(make_pair(string("right"), string("右边")));
dict.Insert(make_pair(string("mid"), string("中间")));
HashNode<string, string>* ret = dict.Find("left");
cout << ret->_kv.second << endl;
}
}
namespace BUCKET
{
using namespace std;
template<class K, class V>
class HashNode
{
public:
pair<K, V> _kv;
HashNode<K, V>* _next;
HashNode(const pair<K, V>& kv)
:_kv(kv)
, _next(NULL)
{}
};
template<class K>
struct __HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
template<>
struct __HashFunc<string>
{
static size_t BRDRHash(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 BRDRHash(key.c_str());
}
};
/*template<class K,class V,class HashFunc == __HashFunc<K>>
struct HashTableIterator
{
typedef HashNode<K, V> Node;
typedef HashTableIterator<K, V, HashFunc> Self;
Node* _node;
HashTable<K, V, HashFunc>* _ht;
Hash
pair<K,V>& operator*()
{
return _node->_kv;
}
pair<K, V>* operator->()
{
return &opertaor*();
}
Self& operator++
{
//1.如果当前桶没走完,继续走
//2.如果当前桶走完了,找下一个不为空的桶
if (_node->_next)
{
_node = _node->_next;
}
else
{
HashFunc hf;
size_t index = hf(_node->_kv.first);
_node = NULL;
for (size_t i = index; i < _ht._tables.size(); i++)
{
if (_ht->_tables[i])
{
_node = _ht->tables[i];
break;
}
}
}
return *this;
}
Self& operator--()
{
}
};
*/
template<class K, class V>
class HashTable
{
typedef HashNode<K, V> Node;
public:
HashTable()
:_n(0)
{}
~HashTable()
{
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
delete cur;
cur = next;
}
_tables[i] = NULL;
}
}
bool Insert(const pair<K, V>& kv)
{
_CheckCapacity();
size_t index = _HashFunc(kv.first, _tables.size());
Node* cur = _tables[index];
while (cur)
{
if (cur->_kv.first == kv.first)
{
return true;
}
cur = cur->_next;
}
//头插
Node* tmp = new Node(kv);
tmp->_next = _tables[index];//??
_tables[index] = tmp;//??
++_n;
return true;
}
Node* Find(const K& key)
{
size_t index = _HashFunc(key, _tables.size());
Node* cur = _tables[index];
while (cur)
{
if (cur->_kv.first == key)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
bool Remove(const K& key)
{
size_t index = _HashFunc(key, _tables.size());
Node* prev = NULL;
Node* cur = _tables[index];
while (cur)
{
if (cur->_kv.first == key)
{
if (prev == NULL)
{
//头删
_tables[index] = cur->_next;
}
else
{
//非头删
prev->_next = cur->_next;
}
delete cur;
return true;
}
prev = cur;
cur = cur->_next;
}
return false;
}
private:
vector<Node*> _tables;
size_t _n;
size_t _HashFunc(const K& key, size_t size)
{
return key % _tables.size();
};
void _CheckCapacity()
{
if (_tables.size() == _n)
{
size_t newsize = GetNextPrime(_tables.size());
vector<Node*> newTables;
newTables.resize(newsize);
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
Node* next = cur->_next;
size_t index = _HashFunc(cur->_kv.first, _tables.size());
cur->_next = newTables[index];
newTables[index] = cur;
cur = next;
}
_tables[i] = NULL;
}
_tables.swap(newTables);
}
}
size_t GetNextPrime(size_t value)
{
/*const int _PrimeSize = 28;
static const unsigned long _PrimeList[_PrimeSize] =
{
53ul, 97ul, 193ul
};*/
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++)
{
if (_PrimeList[i]>value)
{
return _PrimeList[i];
}
}
return _PrimeList[_PrimeSize - 1];
}
};
void Test()
{
HashTable<int, int> ht;
for (size_t i = 0; i < 100; i++)
{
ht.Insert(make_pair(i, i));
}
//HashTable<string, string> dict;
//dict.Insert(make_pair("left", "左边"));
ht.Remove(1);
ht.Find(50);
}
}