由于哈希表的查找高效性,在平时的算法中用的也是比较多。例如:字符串、单词个数的统计,只出现一次字符或者数字的统计,两个集合相同元素的查找等等,还有插入删除的高效(链地址法)都可以用哈希表来解决。缺点可能是需要占用额外的内存空间。
1 原理分析
处理哈希冲突的另一种方法是拉链法,也称为哈希桶。适用于经常进行插入和删除的情况。一方法参考:https://blog.csdn.net/qq_15000103/article/details/80270964
拉链法解决冲突的做法是:将所有关键字为同义词的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组t[0..m-1]。凡是散列地址为i的结点,均插入到以t为头指针的单链表中。t中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。
2 代码实现
//HashTable.h
#pragma once
#include<vector>
#include<utility>
#include<string>
template<class V>
struct HashNode
{
V _v;//set->k;map->kv
HashNode<V>* _next;
HashNode(const V& v)
:_v(v)
, _next(NULL)
{}
};
template<class K>
struct Hash
{
size_t operator()(const K& key)
{
return key;
}
};
template<>
struct Hash<string>//特化,使得缺省时,若调string,则调用此函数
{
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 KeyOfValue, class _HashFunc>//unordered_set<K,V>->HashTable<K,K>;unordered_map<K,V>->HashTable<K,pair<K,V>>
class HashTable;
template<class K, class V, class KeyOfValue, class _HashFunc>
struct _HashTableIterator//单向迭代器
{
typedef HashNode<V> Node;
typedef _HashTableIterator<K, V, KeyOfValue,_HashFunc> Self;