这个算法由google开源,最早在2017年的c++大会上分享过。
hash表的实现,实在是太经典太没什么新意了,但是这个数据结构又是用得太多太基础的组件了,如果有人能够把hashtable做的更快,实在也没理由拒绝。Google实现的这个hash表的性能,请看下图:
(图片引用了Zhihu 流左沙文章内图片)
各种情况下,swisstable比std::unordered_set至少快两倍!!!
低负载情况 | 高负载情况 | |
---|---|---|
找到的情况 | 快2倍以上 | 快6倍 |
找不到的情况 | 快2.5倍 | 快6倍 |
hash表通常号称O(1)的时间复杂度,但是在hash冲突存在的情况下,往往达不到O(1)的时间复杂度。
众所周知(我最喜欢问的面试题),解决hash冲突有以下经典的三种方式:
重点在于,std::unordered_map使用开放地址法来解决hash冲突。
链表最大的问题就在于——在当代的CPU架构下,内存比SSD快100倍,而cpu cache又比内存快100倍,链表对于CPU cache并不友好。因此,cache友好的结构能够提升性能。
Swiss table的关键设计就是——通过相邻地址法来解决hash冲突。一个平坦的内存结构,能够提高cpu cache命中率。
因此,具体的设计细节,都是针对相邻地址法解决hash冲突的具体办法。
swiss hash的大致结构可以表述如下:
struct Item{
uint64_t hashcode; //57bit
void* key;
void* value;
};
#define MAX_ITEMS 1024 /*hash的长度以2的幂对齐*/
struct SwissTable{
Item items[MAX_ITEMS];
uint8_t meta_table[MAX_ITEMS]; //元数据表,用于解决hash冲突
};
通过在key上执行hash函数,得到一个64位的hash值。
把hash值分为高7位和低57位:
hash桶中每个slot对应一个1一个byte的控制字节。
Control byte的高1位用于表示状态,低7位用于存储hashcode的高7位。
状态位分为:
以128bit对齐的连续8字节的control byte称为一个group。
解决hash冲突通常在slot对应的control byte所在的group内解决。
以128bit对齐的原因是,group内的搜索,可以用四条SIMD指令来解决。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。