hash概念
哈希表是一个高效查找的数据结构
查找效率一般是O(1),出现哈希冲突时效率可能会降低
哈希冲突
散列函数有一个共同性质,即函数值应按同等概率取其值域的每一个值。
在哈希表中几个数据可能会对应同一个位置,这种情况就是哈希冲突
解决散列法中出现冲突问题常采用的方法是线性探测法、多重散列法、链地址法
1、线性探测法
mod取模,m为哈希表长度
当出现冲突时,一个一个往后面找空位置,当后面没有空位置了,就会从前面开始找。
这种方法效率比较低
2、二次探测法
双向找存在的空位置
问题:
第一个数据需要找一次,第二个2次,第三个3次
所以需要n(n+1)/2次
3、链地址法
在哈希表每个节点存放一个链表,当发生哈希冲突时,可以直接头插链表前面
缺点:查找的效率大大降低
泛型模板
上述方法都需要对数据进行取模操作,如果不是整数应该怎么办
泛型模板可以把传入的数据,不管是整数还是字符串都可以进行取模操作
template<class K>
struct DefaultHashFunc
{
size_t operator()(const K& key)
{
return (size_t)key;
}
};
template<>
struct DefaultHashFunc<string>
{
size_t operator()(const string& str)
{
// BKDR
size_t hash = 0;
for (auto ch : str)//减少hash冲突的概率
{
hash *= 131;
hash += ch;
}
return hash;
}
};
unordered_set容器
"无序set"容器,跟set很类似,但unordered_set底层是使用哈希表,不会对数据进行排序,有去重的功能
unordered_map 容器
与map类似,都是存储pair<key,value>键对,但没有排序,底层也是哈希
仿函数 重载operator()
在对上面两个容器进行封装时,会出现一个问题
在传数据之前,我们不知道传入的是key还是pair<k,v> ,unordered_set直接取出,那么unordered_map该怎么办?
这时就需要分别在两个容器类中,重载operator(),unordered_set直接返回key,unordered_map返回pair<k,v>对象的first。
struct SetKeyoft
{
const k& operator()(const k& key)
{
return key;
}
};
struct MapKeyoft
{
const k& operator()(const pair<k,v>& kv)
{
return kv.first;
}
};