哈希表在对于查找方面是很快捷方便的,哈希是一个映射,对于关键字映射在哈希表里的位置是随机的,但也是有要求的,对于关键字的映射不能超出表的范围。
但对于不同的关键字,可能会映射到同一个哈希位置上,这样就会产生哈希冲突。哈希冲突只能尽可能的减少,但是不能避免。
处理哈希冲突的方法:
1、开放定址法
该处理方法有线性探测再散列和二次探测再散列两种处理方式,前者是将出现的冲突进行+1,如果下一个仍旧冲突,在原本的位置上+2,以此类推,直到找到一个位置为空的位置上将关键字放上,后者则是在出现冲突之后加上一次的平方,若之后的位置上仍然出现冲突,则在原本的位置上向后移动2的平方,冲突几次就是几的平方。
2、链地址法
将所有的相同性质的关键字放在同一条线性链表上,即在哈希表的每个地址下面挂上一条链表。一般情况下我们不会一下子去把空间开的超级大,所以存在扩容这些,那么就可以考虑vector来实现,只不过每个元素装的是一个链表。
开链法实现如下:
//拉链法哈希表实现
namespace HASH_BUCKET
{
template<class V>
struct HashNode
{
V _v;
//ValueType _valueField;
HashNode<V>* _next;
HashNode(const V& v)
:_v(v)
, _next(NULL)
{}
};
template<class K, class V,class KeyOfValue>
class HashTable
{
typedef V ValueType;
typedef HashNode<V> Node;
public:
HashTable()
:_size(0)
{}
//插入,无法插入重复的
bool Insert(const ValueType& valueField)
{
KeyOfValue kov;
CheckCapacity();//检查容量是否足够
size_t index = HashFunc(kov(valueField), _tables.size());//计算定位的位置
Node* cur = _tables[index];//取得当前未插入的结点的位置
while (cur)
{
if (kov(cur->_v) == kov(valueField))
return false;
cur = cur->_next;
}
Node* node = new Node(valueField);//创建该节点
node->_next = _tables[index];//将该结点挂在对应的位置下面
_tables[index] = node;
++_size;
return true;
}
void CheckCapacity()
{
KeyOfValue kov;
//如果size等于0则第一次开辟空间为10
if (_tables.size() == 0)
{
_tables.resize(10,NULL);
}
else if (_size==_tables.size())
{
size_t newsize = _tables.size() * 2;
vector<Node*> newtables;
newtables.resize(newsize, NULL);
for (size_t i = 0; i < _tables.size(); i++)
{
Node* cur = _tables[i];
while (cur)
{
size_t index = HashFunc(kov(cur->_v), newsize);
Node* next = cur->_next;
cur->_next = newtables[index];
newtables[index] = cur;
cur = next;
}
_tables[i] = NULL;
}
_tables.swap(newtables);
}
}
bool Find(const K& key)
{
KeyOfValue kov;
size_t index = HashFunc(key);
Node* cur = _tables[index];
while (cur)
{
if (kov(cur->_v) == key)
return true;
cur = cur->_next;
}
return false;
}
bool Rremove(const K& key)
{
size_t index = HashFunc(key);
KeyOfValue kov;
Node* cur = _tables[index];
while (cur!=NULL)
{
if (kov(cur->_v) == key)
{
_tables[index] = cur->_next;
delete cur;
return true;
}
else
{
Node* prev = cur;
cur = cur->_next;
while (cur)
{
if (kov(cur->_v) == key)
{
prev->_next = cur->_next;
delete cur;
return true;
}
cur = prev;
cur = cur->_next;
}
return false;
}
}
return false;
}
size_t HashFunc(const K& key)
{
return key%_tables.size();
}
size_t HashFunc(const K& key, size_t size)
{
return key % size;
}
private:
vector<Node*> _tables;
size_t _size;//表的大小
};
template<class K,class V>
struct MapKeyOfValue
{
const K& operator()(const pair<K, V>& kv)
{
return kv.first;
}
};
template<class K>
struct SetKeyOfValue
{
const K& operator()(const K& key)
{
return key;
}
};
void test()
{
HashTable<int, int, SetKeyOfValue<int>> table;
table.Insert(10);
table.Insert(54);
table.Insert(22);
table.Insert(22);
table.Insert(23);
table.Insert(53);
table.Insert(82);
cout << table.Find(22) << endl;
cout << table.Find(199) << endl;
cout << table.Find(54) << endl;
cout << table.Find(23) << endl;
cout << table.Find(82) << endl;
cout << table.Find(10) << endl;
cout << table.Find(53) << endl;
cout << table.Rremove(53) << endl;
cout << table.Rremove(22) << endl;
cout << table.Rremove(199) << endl;
cout << table.Rremove(54) << endl;
cout << table.Rremove(23) << endl;
}
}