散列查找-(二)基本概念

(一)入门理解

(二)基本概念

(三)散列函数的构造方法

(四)处理冲突的方法

(五)散列表的性能分析

(六)应用实例

 

散列是一种重要的查找方法

  • 散列表
  • Hash Table
  • 哈希表
  • 关键字-地址转化法

以上其实是同一个东西


其中的转化方法叫做散列函数(哈希函数)

关键字→地址的转化方法

小明查字典:把帅联系到s,美→M,良→L,你总结到方法了吗?

小王说出三个8,也许下次他说手机号“133-3333-4444”会说:“1,6个3,4个4”,少说(11-7=5)个字!你总结到方法了吗?


但是!!!如果把这种方法用在全部汉字和全部手机号上呢?

散列表的空间是m,填入表的元素个数是n,那么填装因子α就是n/m

小明:字典有5000个汉字,而字母只有26位,填装因子α就是5000/26远远大于1,每个字母肯定有对应的汉字,也就是100%的满分空间利用,但也有就是巨大的0分冲突,s可能是帅(shuai),可能是思(si),可能是傻(sha)

小王:手机号是11位(189-2345-6314),按照小王的方法,1个数字对于3个汉字(一个一,一个八,一个九,一个二...),要36个汉字念完,而每个汉字可能性有11种(一,二.,三......九,零,个)

我们讲期望,不讲极端,填装因子α(10的11次方)/(11的36次方)约等于0,没有冲突100分,但是11的36次方是多少空间呢?

填装因子α必须小于1,在0.5~0.8为宜。所以,小明和小王的转化方法全部不行,无法普适

我有一个朋友,他不明白HashMap加载因子具体为什么是0.75、他百度了一下,说0.75是“哈希冲突”和“空间利用率”矛盾的一个折衷。


总结就是哈希要做到两点:

好的散列函数(好的方法)

制定解决冲突的方法


最后来看一个好的散列方法的例子:

{18,23,11,20,2,7,27,30,42,15,34}  11个数字 存到LIst[17]数组里去

方法是:数字存在(数字%17)的位置

18%17=1,就把18放在List[1]里面;23%17=6,就把23放在List[6]里面;

α=11/17≈0.6  很可以


这边就有疑问了,我为什么要把11个数字倒腾为17个呢,我直接11个不香吗?

直接把元素变成地址不香吗?为什么要用Hash呢?为什么要用关键字-地址转化法呢?

因为,地址是可以直接读取的,很快。

而且这个栗子是数量小,才11个数字,假设是身份证呢?00000000000000000到99999999999999999?

你既要能存下,又要分分钟快速增删改

数组:list[99999999999999999]?

链表:绕地球3圈?

树:整棵树的叶子都在换位置,换着换着就缠在一起了

再夸张一点的例子,身份证前6位000000~999999可以定位到500个市,每个市都有档案。

然后的4位是出生年,每一年档案分开来,1900年到2020年,也就120个房间

然后的4位是出生年:每个房间366个抽屉,放月和日

最后4位就是最多10000种可能,但是此时我觉得可能分下来也就10个吧,为了节省空间,我干脆就在抽屉随便放了,随便放也是一种方法,但牺牲了极小部分的寻址速度

那我填装表的元素正好能放得下呢?为什么要用Hash呢?为什么要用关键字-地址转化法呢?

Java的HashCode的大小暂不清楚,但是C的指针地址有4个字节,32位,2的32次方就是:4294967296

也就是说,你的地址大小就这么大,一个结构体(对象)如果是64字节或者更大,那其实放的也不多

而且用地址作为元素,至少元素要很均匀吧,如果1亿个元素是一样的。。。。那


因为不清楚JVM和底层,以下我就有点乱了,先留着

java中的hashcode不一定是内存地址,至少不全是内存地址,因为有冲突,有冲突的对象的hashcode是一样的

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值