首页 > 编程语言 >常见的哈希算法和应用

常见的哈希算法和应用

时间:2023-04-17 17:56:17浏览次数:49  
标签:hash key 常见 算法 collis 哈希 ns

哈希算法经常会被用到,比如我们Go里面的map,Java的HashMap,目前最流行的缓存Redis都大量用到了哈希算法。它们支持把很多类型的数据进行哈希计算,我们实际使用的时候并不用考虑哈希算法的实现。而其实不同的数据类型,所使用到的哈希算法并不一样。

DJB

下面是C语言实现。初始值是5381,遍历整个串,按照hash * 33 +c的算法计算。得到的结果就是哈希值。

unsigned long
    hash(unsigned char *str)
    {
        unsigned long hash = 5381;
        int c;

        while (c = *str++)
            hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

        return hash;
    }

  

里面涉及到两个神奇的数字,5381和33。为什么是这两个数?我还特意去查了查,说是经过大量实验,这两个的结果碰撞小,哈希结果分散。

还有一个事情很有意思,乘以33是用左移和加法实现的。底层库对性能要求高啊。

 

DJB 在 Redis中的应用

在Redis中,它被用来计算大小写不敏感的字符串哈希。

static uint32_t dict_hash_function_seed = 5381;
/* And a case insensitive hash function (based on djb hash) */
unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len) {
    unsigned int hash = (unsigned int)dict_hash_function_seed;

    while (len--)
        hash = ((hash << 5) + hash) + (tolower(*buf++)); /* hash * 33 + c */
    return hash;
}

 

算法和之前的一样,只是多了一个tolower函数把字符转成小写。

Java 字符串哈希

看了上面的再看Java内置字符串哈希就很有意思了。Java对象有个内置对象hash,它缓存了哈希结果,如果当前对象有缓存,直接返回。如果没有缓存,遍历整个字符串,按照hash * 31 + c的算法计算。

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

  

和DJB相比,初始值从5381变成了0,乘的系数从33变成了31。

FNV

字符串每一位都看成是一个数字,32位的话看成是16777169进制的数字,计算当前串的哈希值就是在把当前串转成10进制。

const primeRK = 16777619

// hashstr returns the hash and the appropriate multiplicative
// factor for use in Rabin-Karp algorithm.
func hashstr(sep string) (uint32, uint32) {
    hash := uint32(0)
    for i := 0; i < len(sep); i++ {
        hash = hash*primeRK + uint32(sep[i])
    }
    var pow, sq uint32 = 1, primeRK
    for i := len(sep); i > 0; i >>= 1 {
        if i&1 != 0 {
            pow *= sq
        }
        // 只有32位,超出范围的会被丢掉
        sq *= sq
    }
    return hash, pow
}

 

这个算法的厉害之处在于他可以保存状态。比如有个字符串ab,它的哈希值是a*E+b=HashAB,如果计算bc的哈希值,可以利用第一次计算的结果(HashAB-a*E)*E+c=HashBC。这么一个转换例子里是两个字符效果不明显,如果当前串是100个字符,后移一位的哈希算法性能就会快很多。

在Golang里面字符串匹配算法查找用到了这个。

Thomas Wang’s 32 bit Mix Function

前面说的都是字符串的哈希算法,这次说整数的。

public
int hash32shift(int key)
{
    key = ~key + (key << 15); // key = (key << 15) - key - 1;
    key = key ^ (key >>> 12);
    key = key + (key << 2);
    key = key ^ (key >>> 4);
    key = key * 2057; // key = (key + (key << 3)) + (key << 11);
    key = key ^ (key >>> 16);
    return key;
}

 

Redis对于Key是整数类型时用了这个算法。

Murmur

就纯哈希算法来说,这个算法算是综合能力不错的算法了。碰撞小、性能好。

Hash           Lowercase      Random UUID  Numbers
=============  =============  ===========  ==============
Murmur            145 ns      259 ns          92 ns
                    6 collis    5 collis       0 collis
FNV-1a            152 ns      504 ns          86 ns
                    4 collis    4 collis       0 collis
FNV-1             184 ns      730 ns          92 ns
                    1 collis    5 collis       0 collis▪
DBJ2a             158 ns      443 ns          91 ns
                    5 collis    6 collis       0 collis▪▪▪
DJB2              156 ns      437 ns          93 ns
                    7 collis    6 collis       0 collis▪▪▪
SDBM              148 ns      484 ns          90 ns
                    4 collis    6 collis       0 collis**
SuperFastHash     164 ns      344 ns         118 ns
                   85 collis    4 collis   18742 collis
CRC32             250 ns      946 ns         130 ns
                    2 collis    0 collis       0 collis
LoseLose          338 ns        -             -
               215178 collis

 

一般在分布式系统中用的比较多。对于一个Key做哈希,把不同的请求转发到不同的服务器上面。

推荐一个Go的实现

CRC32

CRC32的哈希碰撞和murmur的差不多,但是CRC32可以使用CPU的硬件加速实现哈希提速。

在Codis上就使用了这个哈希算法做哈希分片,SlotId= crc32(key) % 1024

Codis使用Go语言实现,CRC32算法直接用了Go的原生包hash/crc32。这个包会提前判断当前CPU是否支持硬件加速:

func archAvailableIEEE() bool {
    return cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41
}

 

memhash

Go语言内置的哈希表数据结构map,也是一个哈希结构,它内置的哈希算法更讲究。

这里用到的哈希算法是memhash,源代码在runtime/hash32.go里面。它基于谷歌的两个哈希算法实现。大家有兴趣的可以去研究下具体实现。

// Hashing algorithm inspired by
//   xxhash: https://code.google.com/p/xxhash/
// cityhash: https://code.google.com/p/cityhash/

 

memhash在具体实现时也用到了硬件加速。如果硬件支持,会用AES哈希算法。如果不支持,才会去用memhash。

func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
    if GOARCH == "386" && GOOS != "nacl" && useAeshash {
        return aeshash(p, seed, s)
    }
    h := uint32(seed + s*hashkey[0])

 

标签:hash,key,常见,算法,collis,哈希,ns
From: https://www.cnblogs.com/binyue/p/17326639.html

相关文章

  • 实验一 密码引擎-4-国䀄算法交叉测试
    目录1在Ubuntu中使用OpenSSL用SM4算法加密上述文件,然后用龙脉eKey解密,提交代码和运行结果截图2在Ubuntu中基于OpenSSL产生一对公私钥对(SM2算法)2.1创建EC参数和原始私钥文件2.2将原始的私钥文件,转换为pkcs8格式:2.3利用原始的私钥,生成对应的公钥:3在Ubuntu中使用OpenSSL用SM3算......
  • 计算机算法设计与分析(第5版)PDF
    《计算机算法设计与分析(第5版)》是2018年电子工业出版社出版的图书,作者是王晓东。整本书的结构是:先介绍算法设计策略思想,然后从解决经典算法问题来学习,通过实践的方式去学习算法。网络上许多的算法文章都出自于这本书,该书成为了很多开发者学习算法的典藏,网上一直找不到这本书第五......
  • 初探富文本之OT协同算法
    初探富文本之OT协同算法OT的英文全称是OperationalTransformation,是一种处理协同编辑的算法。当前OT算法用的比较多的地方就是富文本编辑器领域了,常用于作为实现文档协同的底层算法,支持多个用户同时编辑文档,不会因为用户并发修改导致冲突,而导致结果不一致甚至数据丢失的问题。描述......
  • 常见漏洞描述及修复方式
    弱口令漏洞描述由于系统中存在有弱口令,导致攻击者通过弱口令可轻松登录系统中,从而进行下一步的攻击,如上传webshell,获取敏感数据!另外攻击者利用弱口令登录网站管理后台,可任意增删改等操作,从而造成负面影响!整改建议1、建议强制用户首次登录时修改默认口令,或是使用用户自定义初......
  • python中列表常见的操作方法
    一、添加元素的方法1.append()方法#l.append()用于在列表末尾添加新的对象,返回值:该方法无返回值,但是会修改原来的列表l=[1,2,3,4,5]l1=[6,7,8]l2={"age":"12"}l3='年后,nihao'l4=('height','name')#增加列表l.append(l1)print(l)#......
  • MATLAB:基于模型预测算法的含储能微网双层能量管理模型
    储能优化模型预测控制MPC微网优化调度能量管理 MATLAB:基于模型预测算法的含储能微网双层能量管理模型参考文档:《ATwo-layerEnergyManagementSystemforMicrogridswithHybridEnergyStorageconsideringDegradationCosts》完全复现主要内容:代码微网双层优化调......
  • MATLAB 蚁群算法 配网重构 故障恢复 最小失电负荷 以提高供电可靠性和降低线损为目标,
    MATLAB蚁群算法配网重构故障恢复最小失电负荷以提高供电可靠性和降低线损为目标,建立配电网重构的优化模型,对算法进行综合比较,选取蚁群算法进行网络重构的优化。以IEEE33节点的配电网重构为算例,验证了本模型的可用性及利用蚁群算法解决重构算法的高效性。ID:4865067112444......
  • 基于多目标算法的冷热电联供型综合能源系统运行优化
    多目标粒子群  冷热电联供  综合能源系统  运行优化关键词:综合能源冷热电三联供 粒子群算法多目标优化参考文档:《基于多目标算法的冷热电联供型综合能源系统运行优化》仿真平台:MATLAB平台采用粒子群实现求解优势:代码注释详实,适合参考学习,非目前烂大街的版本,程序......
  • 考虑IEEE33节点系统使用基本环矩阵编码的智能优化算法在处理配电网重构问题
    matlab 改进灰狼算法 含分布式电源 配电网重构考虑IEEE33节点系统使用基本环矩阵编码的智能优化算法在处理配电网重构问题中,通常使用无序的解空间,解空间中局部峰值较多,使得智能优化算法难以发挥自身优势,耗时严重且难以寻找到最优解。针对以上问题,提出一种有序环网编码方式......
  • 基于改进粒子群算法的微电网多目标优化调度
    基于改进粒子群算法的微电网多目标优化调度有传统算法和改进算法对比,微电网优化调度作为智能电网优化的重要组成部分,对降低能耗、环境污染具有重要意义。微电网的发展目标既要满足电力供应的基本需求,又要提高经济效益和环境保护。对此,提出了一种综合考虑微电网系统运行成本和环......