哈希之开散列和闭散列

哈希表是一种能快速定位数据的结构,通过哈希函数将元素的关键码映射为存储位置。然而,哈希冲突是不可避免的问题,当不同元素映射到同一位置时,可通过开放地址法(如线性探测再散列)或链地址法来解决。开放地址法可能导致数据堆积,降低查找效率;而链地址法虽然增加存储开销,但能有效解决溢出问题。负载因子是衡量哈希表拥挤程度的指标,应保持在一定范围内以减少冲突。
摘要由CSDN通过智能技术生成

以下内容转载自 https://blog.csdn.net/Yinghuhu333333/article/details/81364739

目的:实现一种结构,不经过任何比较,一次直接得到想要的元素。通过某种函数使元素的存储位置与它的关键码之间建立一种一一映射的关系。那么就可以在查找时快速的找到需要的元素。


哈希概念

哈希之散列方法:

  • 插入元素时:根据需要插入元素的值,通过某种计算得出元素的存储位置,将该元素插入到其对应的位置。
  • 查找元素时:根据需要查找的元素进行某种计算得到其存储位置,将该位置的元素与查找的元素进行比较,若相同则查找成功。

例如:数据集合为{180,750,460,430,800,600,541}
哈希函数:Hash(key) = key%m;(m为内存单元的个数)
假设在该例子中,m为12;
Hash(180) = 0;
Hash(750) = 6;
Hash(460) = 4;
Hash(430) = 10;
Hash(800) = 8;
Hash(603) = 3;
Hash(541) = 1;
所以这些数据集合在内存中的存储为:
这里写图片描述
可是如果数据有冲突 了应该怎么办???

哈希冲突

哈希冲突:对于值不相同的元素但是却有相同的哈希值。
例如:对于两个元素a,b并且a!=b
但是Hash(a) == Hash(b);
不同的元素通过相同的哈希函数得到相同的哈希地址。


引起哈希冲突的原因:哈希函数设计的不够合理。
哈希函数的设计原则:

  • 如果哈希表允许容纳的元素个数为m,那么元素的值域为0~m-1。
  • 哈希函数计算出来的地址尽量均匀的分布整个空间之中。

常见的哈希函数

  • 直接定制法:
    即取元素的某个线性函数为散列地址:Hash(key) = A*key +B;
    例如:找出字符串中只出现一次的字符。时间复杂度为O(N),空间复杂度为:O(1);(就可以使用该方法,开辟一个256个元素的数组,进行统计每个元素出现的次数)
    优点:简单,均匀
    适合于查找比较小而且连续的情况。
  • 除留取余法:(比较常用的方法)
    Hash(key) = key % p;(p <= m && p 质数),m为散列表中允许的地址个数。
  • 平方取中法:
    对数据进行平方,然后取数据的中间3位为哈希地址。
    适合于:不知道数据的分布情况,但是数字又不是很大的情况

若哈希函数设计的非常合理,那么产生哈希冲突的概率就非常低,但是哈希冲突是无法避免的。


哈希冲突的处理:
方法一:
闭散列(即开放地址法):当发生哈希冲突时,如果该哈希表还没有被填满,那么就把该元素放到哈希表的下一个空闲的位置。
线性探测法查找下一个位置:
例如:关键码集合为:{37,25,14,36,49,57,11},设表的长度为12,Hash(key) = key%p(p = 11);
Hash(37) = 4;
Hash(25) = 3;
Hash(14) = 3;
Hash(36) = 3;
Hash(49) = 5;
Hash(57) = 2;
Hash(11) = 0;
很明显:这组数据的哈希地址有冲突。
在插入时,如果该位置已经有元素了,就从该位置起向后找,找到一个空闲的位置就进行插入。
如下图所示:
线性探测法
优点:简单 易懂
缺点:一旦发生了哈希冲突,所有的冲突连接在一起,很容易产生数据”堆积”。即不同的数据占用可以利用的位置,就使得寻找其余数据的位置需要进行多次比较,就会导致查找的效率降低。


负载因子
散列表的负载因子的值为:α = 填入表中的元素个数 / 散列表的长度。
分析:由于表长是定值,那么α就与”填入表中的元素个数”成正比。所以,α越大,就说明填入表中的元素个数越多,那么产生冲突的可能性就越大;反之,α越小,就说明填入表中的越少,产生的冲突就越小,但是可能浪费的空间就越多。
对于开放地址法:负载因子特别重要,应该限制在07-0.8之内。若超过0.8,就可能产生冲突的概率非常大,那么CPU缓存不命中率也就越高。


二次探测法:
就是当有哈希冲突时,寻找下一个空闲位置时,首先在该位置处加1的平方,若加1的平方的位置处依然有元素,那就加2的平方,知道找到一个空闲的位置为止。


方法2:开散列法(哈希桶):又名链地址法,先用哈希函数计算每个数据的散列地址,把具有相同地址的元素归于同一个集合之中,把该集合处理为一个链表,链表的头节点存储于哈希表之中。
例如:还是上面闭散列中的例子,当使用开散列的方法后,其每个元素的存储为下图所示:
哈希桶

由此可见:开散列法有效的解决了数据溢出,不过需要增设链接指针,增加了存储的开销。但是,总体而言,效率还是快的多。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值