哈希冲突概率计算及python仿真

news2024/11/19 4:32:27

目录

1. 前言

2. 生日问题

3. 哈希冲突问题

4. 简易python仿真

5. 从另一个角度看哈希冲突概率


1. 前言

        Hash函数不是计算理论的中基本概念,计算理论中只有单向函数的说法。所谓的单向函数,是一个复杂的定义,严格的定义要参考理论或者密码学方面的书籍。用“人类”的语言描述单向函数就是:如果某个函数在给定输入的时候,很容易计算出其结果来;而当给定结果的时候,很难计算出输入来,这就是单向函数。各种加密函数都可以被认为是单向函数的逼近。Hash函数(或者成为散列函数)也可以看成是单向函数的一个逼近。即它接近于满足单向函数的定义。

        Hash函数还有更通俗的理解方式,即它代表的是一种关于数据的压缩映射。实际中的Hash函数是指把一个大范围映射到一个小范围。把大范围映射到一个小范围的目的往往是为了节省空间,使得数据容易保存。除此以外,Hash函数往往应用于查找上。所以,在考虑使用Hash函数之前,需要明白它的几个限制:

        (1) Hash的主要原理就是把大范围映射到小范围;所以,你输入的实际值的个数必须和小范围相当或者比它更小。不然冲突就会很多。

        (2) 由于Hash逼近单向函数;所以,你可以用它来对数据进行加密。

        (3) 不同的应用对Hash函数有着不同的要求;比如,用于加密的Hash函数主要考虑它和单向函数的差距,而用于查找的Hash函数主要考虑它映射到小范围的冲突率。

        Hash函数应用的主要对象是数组(比如,字符串),而其目标一般是一个int类型。

        一般的说,Hash函数可以简单的划分为如下几类:
        1. 加法Hash;
        2. 位运算Hash;
        3. 乘法Hash;
        4. 除法Hash;
        5. 查表Hash;
        6. 混合Hash;
 

        本文主要讨论关于哈希概率的计算及其简易python仿真。

2. 生日问题

        从数学上来说,哈希冲突概率问题其实是一个更通俗的所谓的“生日问题(birthday problem)”的一般化。

        生日问题:假定人群中生日在一年的365天中分配是符合均一分布(uniform distribution)的(换句话说,1年的365天中每天出生的人数统计意义上是相等的)。在k个人的聚会中,至少有2个人生日是同一天的概率有多大?进一步,至少有2个人生日是同一天的概率超过50%的最小的N是多少?

        这个问题的结果有些反直觉,所以如果不经过严格的计算,很难猜到哪怕是大致接近的答案。以下来讨论如何计算这个概率。

        我们要计算的是至少有两个人发生生日冲突的概率,但是直接计算这个不容易。作为一个概率计算中的常用技巧,我们考虑“至少有两个人发生生日冲突”这个事件的补事件--即任何两人之间都不发生生日冲突--的概率。

        以下的描述中用生日冲突表示两个人生日为同一天。

        考虑第1个人,很显然TA不会与任何人生日冲突

        考虑第2个人,TA与第一个人不发生生日冲突的概率为很显然为1-\frac{1}{365} = \frac{365-1}{365}

        考虑第3个人,TA与前两个人发生生日冲突的概率为很显然为(1-\frac{2}{365}) = \frac{365-2}{365}

        ...

        考虑第k个人,TA与前(k-1)个人发生生日冲突的概率为很显然为\frac{365-(k-1)}{365}

        因此k个人不发生生日冲突的概率为:

                \frac{365}{365}\frac{364}{365}\cdots\frac{365-(k-1)}{365} = \prod \limits_{l=0} \limits^{k-1} \frac{l}{365}

        因此,最少有两个人的生日恰好为同一天的概率则是:P_{collision} = 1 - \prod \limits_{l=0} \limits^{k-1} \frac{l}{365}

3. 哈希冲突问题

        假定哈希函数在将数据从一个大的空间(记为输入空间)压缩映射到一个小的空间(记为目标空间)时,是遵从均一分布的话,那么哈希冲突(任意两个输入空间的数据映射到目标空间中的相同数据)的概率问题,其实就是以上生日问题中发生生日冲突的概率问题的一般化问题。只不过目标空间的大小从生日问题中的365变为一般化的N。

        即目标空间大小为N时的一般化的哈希冲突概率为:

        ​​​​​​​        P_{collision, N} = 1 - \prod \limits_{l=0} \limits^{k-1} \frac{l}{N}

        在N非常大的时候,计算上式右边的第2部分会比较慢,所幸的是,这个式子可以很好地进行如下近似: 

                \prod \limits_{l=0} \limits^{k-1} \frac{l}{N} = 1 - \prod \limits_{l=0} \limits^{k-1} \frac{l}{N} \cong 1 - e^{-\frac{k(k-1)}{2N}}

4. 简易python仿真

 

# -*- coding: utf-8 -*-
"""
Created on Mon Nov 21 13:44:55 2022

@author: chenxy

ref: https://preshing.com/20110504/hash-collision-probabilities/
"""
import math
import numpy as np
import matplotlib.pyplot as plt
import time
def probCollision(N,k):
    probCollision = 1.0
    for j in range(k):
        probCollision = probCollision * (N - j) / N
    return 1 - probCollision

def probCollisionApproximation(N,k):
    # return 1 - math.exp(-0.5 * k * (k - 1) / N)
    return 1 - np.exp(-0.5 * k * (k - 1) / N)

if __name__ == '__main__':
    
    tstart=time.time()   
    Pcollision = [0]
    for k in range(1,100):
        Pcollision.append(probCollision(365, k))
        print('k = {0}, Pcollision[k] = {1}'.format(k,Pcollision[k]))
    tstop=time.time()
    print('Total elapsed time = {0} seconds'.format(tstop-tstart))
    
    tstart=time.time() 
    Pcollision2 = [0]    
    for k in range(1,100):
        Pcollision2.append(probCollisionApproximation(365, k))
        print('k = {0}, Pcollision2[k] = {1}'.format(k,Pcollision2[k]))
    tstop=time.time()
    
    print('Total elapsed time = {0} seconds'.format(tstop-tstart))

    plt.plot(Pcollision)
    plt.plot(Pcollision2)

运行结果如下:

。。。
k = 17, Pcollision2[k] = 0.31106113346867104
k = 18, Pcollision2[k] = 0.34241291970846444
k = 19, Pcollision2[k] = 0.37405523755741676
k = 20, Pcollision2[k] = 0.40580512747932584
k = 21, Pcollision2[k] = 0.4374878053458634
k = 22, Pcollision2[k] = 0.4689381107801478
k = 23, Pcollision2[k] = 0.5000017521827107
k = 24, Pcollision2[k] = 0.5305363394090516
k = 25, Pcollision2[k] = 0.5604121995072768

。。。

 由以上仿真结果可以看出:

(1)上一节所说的近似方法的准确度非常高,两种方法计算结果从图上看几乎一致

(2)生日冲突概率在23个人时就超过50%了!这意味着23个人聚会时,至少有两个人生日为同一天的概率就超过50%了。想一想一年有365天,区区23个人凑在一起就有超过一半的概率会出现某两个人生日为同一天,是不是有点神奇?

        进一步,对任意N进行仿真,我们可以发现,对任意N来说,冲突概率曲线都是以上这个形状。这意味着,冲突概率其实可以表达为归一化数(k/N)的函数,与具体的k和N其实是无关的。

 

5. 从另一个角度看哈希冲突概率

        本节从另一个角度来考察哈希冲突概率。

        给定一个目标空间的大小N,随机地进行从输入空间进行数据采样并将其映射到目标空间,需要多少个输入数据才能将目标空间填满呢?目标空间的填充率与冲突概率之间是什么关系呢?

        以下针对这个问题做一个蒙特卡洛仿真。代码如下:

# -*- coding: utf-8 -*-
"""
Created on Sat Nov 26 10:04:08 2022

@author: chenxy
"""


# generate random 160 bits key

import numpy as np
import random
from collections import defaultdict
import time
import matplotlib.pyplot as plt

def key160_gen() -> int:
    """
    Generate one random 160 bits key

    Returns
    -------
    int
        160 bits key.

    """
    return random.randint(0,2**160-1)

def hash_sim(cam_depth):

    hcam = np.zeros((cam_depth,))
    key_cnt       = 0
    query_ok_cnt  = 0
    collision_cnt = 0
    camfill_cnt   = 0
        
    while 1:
        key_cnt += 1
        key = key160_gen()    
        key_hash = hash(key) %(cam_depth)
        # print('key = {0}, key_hash = {1}'.format(key,key_hash))
        
        if key == hcam[key_hash]:
            query_ok_cnt += 1
        else:
            if hcam[key_hash]==0:
                camfill_cnt += 1
            else:
                collision_cnt += 1
            hcam[key_hash] = key
    
        # if key_cnt %4096 == 0:
        #     print('key_cnt = {0}, camfill_cnt = {1}'.format(key_cnt,camfill_cnt))
    
        if camfill_cnt == cam_depth:
            # print('CAM has been filled to full, with {0} key operation'.format(key_cnt))
            break        
        
    return key_cnt, collision_cnt    

rslt = []
for k in range(10,20):
    tStart = time.time()        
    cam_depth = 2**k
    key_cnt,collision_cnt = hash_sim(2**k)
    tElapsed = time.time() - tStart            
    print('cam_depth={0}, key_cnt={1}, collision_prob={2:4.3f}, tCost={3:3.2f}(sec)'.format(cam_depth,key_cnt,collision_cnt/key_cnt,tElapsed))
    
    rslt.append([cam_depth,key_cnt])

rslt = np.array(rslt)    
plt.plot(rslt[:,0],rslt[:,1])

 运行结果如下:

cam_depth=1024, key_cnt=6010, collision_prob=0.830, tCost=0.07(sec)
cam_depth=2048, key_cnt=16034, collision_prob=0.872, tCost=0.17(sec)
cam_depth=4096, key_cnt=30434, collision_prob=0.865, tCost=0.30(sec)
cam_depth=8192, key_cnt=89687, collision_prob=0.909, tCost=0.87(sec)
cam_depth=16384, key_cnt=149980, collision_prob=0.891, tCost=1.15(sec)
cam_depth=32768, key_cnt=314527, collision_prob=0.896, tCost=2.38(sec)
cam_depth=65536, key_cnt=866673, collision_prob=0.924, tCost=6.48(sec)
cam_depth=131072, key_cnt=1518369, collision_prob=0.914, tCost=11.08(sec)
cam_depth=262144, key_cnt=3657451, collision_prob=0.928, tCost=26.70(sec)
cam_depth=524288, key_cnt=6648966, collision_prob=0.921, tCost=48.48(sec)

         以上仿真结果表明,要让哈希表以满填充状态工作的话,哈希冲突概率大概为90%左右,也就是说放入哈希表的操作大概每10次会发生9次冲突!基于哈希表的应用中最重要的问题就是如何解决哈希冲突的问题。

参考文献:

[1] Hash Collision Probabilities (preshing.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/106985.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

老板,明年我用Seata搞定分布式事务管理的规范化建设 | 中篇

辞旧迎新,22年要结束了,明年做什么想好了嘛?要不要用 Seata 搞定公司分布式事务管理的规范化建设? 欢迎关注微信公众号「架构染色」交流和学习 一、背景 在上一篇《明年用Seata搞定分布式事务管理的规范化建设 | 上篇》 中介绍了…

低成本、高效率!华为云桌面助力企业数字化转型

在云计算飞速发展的今天,传统办公设备体积大、能耗高、维护难、更新换代快等问题日益凸显,而基于云计算平台的虚拟办公系统逐渐被业界接受并得到广泛应用。其中,华为云桌面Workspace既满足了企业移动办公、远程办公、安全办公等要求&#xff…

恒业微晶冲刺创业板上市:计划募资8亿元,戴联平为实控人

12月20日,上海恒业微晶材料科技股份有限公司(下称“恒业微晶”)在深圳证券交易所创业板递交招股书。本次冲刺创业板上市,恒业微晶计划募资8亿元,将用于恒业新型分子筛项目。 据天眼查信息显示,恒业微晶成立…

Servlet中Cookie和Session技术

一、状态管理1.1 现有问题HTTP协议是无状态的,不能保存每次提交的信息如果用户发来一个新的请求,服务器无法知道它是否与上次的请求有联系对于那些需要多次提交数据才能完成的Web操作,比如登录来说,就有问题了。1.2 概念将浏览器与…

牛津大学最新 | LUMix:Mixup改进版,几行代码轻松涨点!

点击下方卡片,关注“自动驾驶之心”公众号ADAS巨卷干货,即可获取点击进入→自动驾驶之心【目标检测】技术交流群后台回复【LUMix】获取论文!!!摘要当使用噪声样本和正则化技术进行训练时,现代深度网络可以更…

云端数据“上榜”了!

背景介绍随着全球特别是北美地区VNF网络应用渐渐地往云上迁移,云环境中更高的性能需求变得越来越迫切。作为一流数据处理中心部门,随着大势所趋,不仅仅专研于裸机的性能数据,也开始关注Intel平台在不同云环境中的性能表现。在DPDK…

外汇天眼:日本央行突然上调收益率目标上限,日元10分钟内涨超2%

12 月 20 日,日本央行公布利率决议,并在货币政策会议上宣布堪称“黑天鹅事件”的重大政策转变。日本央行意外地调整了收益率曲线控制计划,宣布将收益率目标上限从 0.25% 上调至 0.5% 左右,同时又将 1 至 3 月日本国债购买规模提高…

Java当中多态的理解

1. 什么是多态 同一操作,作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。 对应到 Java 里就是针对同一个类型的对象,执行同一个方法,会表现出不同的行为。 简单点说: 就是用基类…

<Linux进程信号>——《Linux》

本节重点: 1. 掌握Linux信号的基本概念 2. 掌握信号产生的一般方式 3. 理解信号递达和阻塞的概念,原理。 4. 掌握信号捕捉的一般方式。 5. 重新了解可重入函数的概念。 6. 了解竞态条件的情景和处理方式 7. 了解SIGCHLD信号, 重新编写信号处理…

面试官:Docker 有几种网络模式?5 年工作经验都表示答不上来。。

docker容器网络 Docker在安装后自动提供3种网络,可以使用docker network ls命令查看 [rootlocalhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE cd97bb997b84 bridge bridge l…

第1章 概述

第一章 概述 考试范围: 1.1-1.10 考试内容: 章节后的Review Terms(名词基本都在课文中) 考试题型: 综合题 Review Terms Database-management system (DBMS) :A collection of interrelated data and a …

信息检索 Information Retrieval

信息检索主要是查找与用户查询相关的文档。 给定:大型静态文档集合 和信息需求(基于关键字的查询) 任务:查找所有且仅与查询相关的文档 典型的 IR 系统: • 搜索一组摘要 • 搜索报纸文章 • 图书馆搜索 • 搜索网络 …

毕业后,我已经离开机械行业转行码农一年多了......

背景 鄙人本科毕业两年有余,机械工程专业,我已经离开机械行业转行码农一年多了。 如果有正在学习的,退学还是千万不要,不过能换专业就换专业,不能换就往机电一体化靠,加上自学编程,以后做嵌入…

计算机毕设Python+Vue野生动物保护资讯管理系统(程序+LW+部署)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

STM32的ST-link调试下载

调试原理 STM32F-10X使用M3内核,该内核支持复杂的同i傲视操作,硬件调试模块允许在取指令(指令单步运行)或访问数据(数据断电时)使得内核停止。在内核停止时,内核状态都可被查询,完成…

范登堡(van den berg)CPT使用记录

前段时间的CPT外业所使用的设备是范登堡的井下式或者说交互式的静力触探仪(CPT),型号是WISON-APB,下面是官网提供的照片。根据官网的介绍,它的探测工具分为三种,分别50KN(3m)、100KN…

KVM部署操作-尚文网络xUP楠哥

~~全文共1250字,阅读需约5分钟。 进Q群11372462,领取专属报名福利! # 安装KVM先决条件 KVM 需要有 CPU 的支持(Intel VT 或 AMD SVM),在安装 KVM 之前检查一下 CPU 是否提供了虚拟技术的支持。 基于 Intel 处理器的…

Qt之使用CQU库快速开发统一风格界面

在使用Qt开发时,肯定是想让开发的项目界面统一风格;不希望每个界面都要程序员用代码去修饰美化以及进行事件处理等等,这样非常繁琐,容易出错而且没有格调;所以我就开发一个动态链接库,封装统一的风格界面、…

尚医通-前端Vue学习(九)

(1)vscode的安装及使用 (2)前端知识-ES6语法知识点 (3)Vue-入门 (4) Vue的生命周期 (5)Vue-Axios的使用 (6)ElemmentUI介绍 &…

Java项目:SpringBoot课程在线学习系统

作者主页:源码空间站2022 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 采用SpringBootSpringMybatisThyeleaf实现的在线学习系统,一共2个角色:管理员与学生。 管理员角色功能: 登录…