之前一篇博文中提过如何用开链法实现哈希表
那么对于哈希表的实现,还有另外一种方法的实现,这就是哈希开放定址法来实现。该方法也是用来处理哈希冲突的。解决思想如下:
现有关键字17,60,29,38
如何确定地址??可以看见该表的长度为11,那么使用关键字取余该表的长度,得到的余数就是该关键字的地址,17则余6,60则余5,29则余7,那么38也余了5,但是5这个地址已经存在关键字了,所以采用一种线性探测的方法,向后寻找一个位置,可以看见6这个地址也已经有了关键字,那就继续向后寻找,直到找到第一个空的位置,存放即可。
线性探测的方法在某种程度上冲突的几率会加大,比如说当有数十个余数相同的关键字时,哈希表的冲突就会尤为的集中,那么还有二次探测的方法,如果当前的位置冲突,向后移动2的冲突次方,即如果第一次冲突就移动1的2次方,第二次再冲突,移动-1的2次方,在该例子中,38就被放到了4这个位子,因为第一次移动是冲突的,则第二次是移动-1次了,即向左移动一个
对于第二种方式对于冲突能够比较分散。
///线性探测//
namespace OPEN{
template<class K>
struct _HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
struct _HashFuncString
{
static size_t BKDRHash(const char * str)
{
unsigned int seed = 131; // 31 131 1313 13131 131313
unsigned int hash = 0;
while (*str)
{
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF);
}
size_t operator()(const string& key)
{
return BKDRHash(key.c_str());
}
};
enum State
{
EMPTY ,
EXIST ,
DELETE,
};
template<class K, class V>
struct HashNode
{
K _key;
V _value;
State _state;//每个位置存了个状态,如果是空就可以扔值进去
HashNode()
:_state(EMPTY)
{}
};
template<class K, class V>
class HashTable
{
typedef HashNode<K,V> Node;
public:
HashTable()
:_size(0)
{}
bool Insert(const K& key, const V& value){
CheckCapacity();
if (Find(key))
{
return false;
}
size_t index =HashFunc(key);
while (_tables[index]._state == EXIST)
{
++index;
if (index == _tables.size())
{
index = 0;
}
}
_tables[index]._key = key;
_tables[index]._value = value;
_tables[index]._state = EXIST;
_size++;
return true;
}
size_t HashFunc(const K& key)
{
return key%_tables.size();
}
//表不能满,满了之后会死循环
Node* Find(const K& key)
{
size_t index = HashFunc(key);
while (_tables[index]._state != EMPTY)
{
if (_tables[index]._key == key)
{
if (_tables[index]._state == EXIST)
{
return &_tables[index];
}
else
{
return NULL;
}
}
++index;
if (_tables.size() == index)
index = 0;
}
return NULL;
}
void CheckCapacity()
{
if (_tables.size()==0||_size*10 / _tables.size() > 7)
{
size_t newsize = _tables.size() * 2;
if (newsize == 0)
{
newsize = 10;
}
HashTable<K, V> newht;
newht._tables.resize(newsize);
for (size_t i = 0; i < _tables.size(); ++i)
{
if (_tables[i]._state == EXIST)
{
newht.Insert(_tables[i]._key, _tables[i]._value);
}
}
_tables.swap(newht._tables);
}
}
bool Remove(const K& key)
{
HashNode* node = Find(key);
if (node)
{
node->_state = DELETE;
--_size;
return true;
}
else
{
return false;
}
}
private:
vector<Node> _tables;
size_t _size;//为什么要加这个size,hash表不是线性的,是映射进去的,这个size代表数据的多少
};
void test()
{
int a[] = { 89, 18,49,58,9,23,45,12,66,67,98};
HashTable<int, int> ht;
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
ht.Insert(a[i], i);
}
}
}
/二次线性探测///
namespace OPEN{
enum State
{
EMPTY,
EXIST,
DELETE,
};
template<class K, class V>
struct HashNode
{
K _key;
V _value;
State _state;//每个位置存了个状态,如果是空就可以扔值进去
HashNode()
:_state(EMPTY)
{}
};
//除string外的类型
template<class K>
struct _HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
struct _HashFuncString
{
static size_t BKDRHash(const char * str)
{
unsigned int seed = 131; // 31 131 1313 13131 131313
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, class __HashFunc = _HashFunc<K> >//针对string需要给一个其他的模板
class HashTable
{
typedef HashNode<K, V> Node;
public:
HashTable()
:_size(0)
{}
bool Insert(const K& key, const V& value){
CheckCapacity();
if (Find(key))
{
return false;
}
size_t i = 1;
size_t index = HashFunc(key);
while (_tables[index]._state == EXIST)
{
index += i*i;
index %= _tables.size();
++i;
if (index == _tables.size())
{
index = 0;
}
}
_tables[index]._key = key;
_tables[index]._value = value;
_tables[index]._state = EXIST;
_size++;
return true;
}
//string不支持
size_t HashFunc(const K& key)
{
__HashFunc hf;//仿函数
return hf(key)%_tables.size();
}
//表不能满,满了之后会死循环
Node* Find(const K& key)
{
size_t index = HashFunc(key);
while (_tables[index]._state != EMPTY)
{
if (_tables[index]._key == key)
{
if (_tables[index]._state == EXIST)
{
return &_tables[index];
}
else
{
return NULL;
}
}
++index;
if (_tables.size() == index)
index = 0;
}
return NULL;
}
void CheckCapacity()
{
if (_tables.size() == 0 || _size * 10 / _tables.size() > 7)
{
size_t newsize = _tables.size() * 2;
if (newsize == 0)
{
newsize = 10;
}
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]._key, _tables[i]._value);
}
}
_tables.swap(newht._tables);
}
}
bool Remove(const K& key)
{
HashNode* node = Find(key);
if (node)
{
node->_state = DELETE;
--_size;
return true;
}
else
{
return false;
}
}
private:
vector<Node> _tables;
size_t _size;//为什么要加这个size,hash表不是线性的,是映射进去的,这个size代表数据的多少
};
/*void test()
{
int a[] = { 89, 18, 49, 58, 9};
HashTable<int, int> ht;
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
ht.Insert(a[i], i);
}
}*/
/*void test()
{
HashTable<string, string, _HashFuncString> dict;
dict.Insert("insert", "插入");
}*/
}