数据结构 - 哈希策略和冲突处理
1. 哈希策略
访问集合中的项的最快的方法,是通过数组和基于数组的列表所支持的随机访问。
假设第一个建是1500,剩下的键是连续性的数字。数组中一个给定的位置,可以通过表达式key - 1500 来计算。这种类型的计算叫做从键到地址的转换,或者称为哈希函数。哈希函数在一个给定的键上执行,并且返回其在数组中的相对位置。使用一种哈希策略的数组,叫做哈希表。
如果哈希函数以常量时间运行,插入、访问和删除相关联的键都是O(1)。
某些哈希函数对不同的键会产生同一个索引,比如哈希函数key % 4 对于键3、5、8、10都会产生唯一索引。但对于健3、4、8、10不能找到唯一的位置。因为,4 和 8 有相同的索引。
像键4 和 8 得到相同的索引,称为冲突。
合适的哈希策略应该由两部分组成:哈希函数 和 冲突处理。
2. 冲突和密度的关系
和第一点中同一个实例,当数组长度为4 时 对3、4、8、10发生冲突。但,若是将数组长度提升为8 时,不再发生冲突。
换句话说,随着密度的降低,冲突的可能性也会减少。但随之增加的是内存的消耗。
装载因子(项的数目除以数组的长度)超过0.5时,发生冲突的可能性是很高的,0.2的装载因子是一个避免冲突的好办法,但会导致巨大的内存成本。
3. 非数字键的哈希
上面的例子键都是整数,当然也可以示字符串。
你可能会尝试返回字符串中的ASCII 值的加和。然而,这种方法对回文字符串、顺序不同的字符串依然会返回相同的键。
另一个问题是,英语中单词的首字符分布并不均匀,比如a、b开头的必然比y、z开头的多。这可能导致由此产生的加和不平衡或偏移,从而导致键的分布集中在整个键集的某一段范围之内。
这种聚簇反过来导致数组中的键的聚簇,而理想情况下,键最好是平均分布于数组之中。为了减少首字母造成的潜在偏移,并且减少回文导致的效果,如果字符串的长度大于某一个阈值,可以将首字母从字符串中丢弃,然后再计算加和。此外,如果字符串超过了某一个长度,可以减去最后一个字符的ASCII值。
不管哈希函数多么高级,哈希表还是可能冲突。下面介绍一些常用的解决办法。
4. 线性探测
对于插入来说,解决冲突最简单的方式,就是从冲突位置开始搜索数组,找到第1个可能的位置,这个过程叫做线性探测。
比如,以 数组长度为6 为例,初始状态数组为:
再向数组插入13 时,13 % 6 = 1,发生冲突。
通过线性探测,向右寻找可用的单元格:
从下标 1 + 1 =2,下标2 已被占用,继续向右 2 + 1 = 3,下标3未被占用,则插入,插入后的状态为:
访问和删除的工作方式是类似的。
对于访问来说,当前的数组单元格为空或者它包含目标项的时候就停止探测。这使得你能够跳过之前占用的单元格以及当前占用的单元格。
对于删除来说,我们也是和访问一样探测。如果找到了目标项,就将单元格的值设置为空。
但是,这种解决冲突的方法也会造成两个问题:
- 在几次插入和删除之后,一些标记为DELETED的单元格可能位于给定的项和其主索引之间。意味着,该项距离其主索引比实际所需的位置要远,因此,增加了平均的整体访问时间。
- 容易导致聚簇。当发生冲突时,会向右探测可用的单元格(意味着连续),很有可能所有的数据全部集中在某一个部分。 – 解决该问题使用二次探测
5. 二次探测
二次探测通过将主索引增加每一次尝试的距离的平方,如果失败了,再次增加距离并尝试。
所以使用的公式是:(k +(-) d^2) % m, d = 1,2,3…m/2-1。
例如:和上一个示例一样,初始状态如下
二次探测步骤如下:同样插入13
k = 13 % 6 = 1
index = (1 + 1^2) % 6 = 2,单元格 2 被占用,继续探测
index = (1 - 1^2) % 6 = 0,单元格 0 未被占用,停止探测,插入13
(如果仍然被占用,步骤应该如下:)
index = (1 + 2^2) % 6 = 5
index = (1 - 2^2) % 6 = 3
… …
插入后的状态为:
5. 链化
另一种解决冲突的方法叫做链化。项都存储在链表或链的一个数组中。每一项的键都会找到该项已经插入到链中的桶或索引。
访问和删除操作每次都会执行如下步骤:
- 计算项在数组中的主索引
- 搜索该项在链表中的索引
如果找到了该项,返回或删除它。
要插入一个项,执行如下步骤:
- 计算项在数组中的主索引
- 如果数组单元格为空,创建一个节点,它带有该项,并且将该节点赋值给单元格,否则产生冲突。在该位置已有的项的头部插入新的项。
同样以上面的例子为例:
初始状态如下:(左侧0-5 可以为一个数组,存放链表的表头)
插入13,主索引 = 13 % 6 = 1,插入后状态:
完!
数据结构 - 哈希策略和冲突处理相关推荐
- 哈希策略_优化哈希策略的简介
哈希策略 总览 用于哈希键的策略可以直接影响哈希集合(例如HashMap或HashSet)的性能. 内置的哈希函数被设计为通用的,并且可以在各种用例中很好地工作. 我们可以做得更好,特别是如果您对用例 ...
- 哈希表、冲突处理方法、查找长度
1.定义 哈希函数就是将关键字和它的存储位置之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应.按这个思想建立的表为哈希表. 2.哈希函数的构造方法 2.1 直接定址法 取关键 ...
- Python中常用的数据结构---哈希表(字典)
Python中常用的数据结构-哈希表(字典) 常用的数据结构有数组.链表(一对一).栈和队列.哈希表.树(一对多).图(多对多)等结构. 在本目录下我们将讲解,通过python语言实现常用的数据结构. ...
- 数据结构——哈希表的详解与实现
数据结构--哈希表(HashTable) 1.前言 当我们频繁的查找数据中的某个元素时,我们通常会选择数组来存放数据,因为数组的的内存是连续的,可以直接通过下标访问数据,但是它添加和删除数据比较麻 ...
- 算法笔记(三)特殊数据结构——哈希表、有序表、并查集、KMP、Manacher、单调栈、位图、大数据类题
layout: post title: 算法笔记(三)特殊数据结构--哈希表.有序表.并查集.KMP.Manacher.单调栈.位图.大数据类题 description: 算法笔记(三)特殊数据结构- ...
- 负载策略_面试官:讲一下什么是负载均衡,什么是轮询策略随机策略哈希策略
什么是负载均衡? 先举个例子吧.以超市收银为例,假设现在只有一个窗口.一个收银员: 一般情况下,收银员平均 2 分钟服务一位顾客,10 分钟可以服务 5 位顾客:到周末高峰期时,收银员加快收银,平均 ...
- java hashtable 数据结构_数据结构--哈希表(Java)
数据结构--哈希表(Java) 介绍 哈希表 底层是 数组加链表 或者是 数组加二叉树 ,一个数组里面有多个链表,通过散列函数来提高效率 代码 package cn.guizimo.hashtab; ...
- Nginx学习之十三-负载均衡-IP哈希策略剖析
前面介绍过nginx负载均衡的加权轮询策略(http://blog.csdn.net/xiajun07061225/article/details/9318871),它是Nginx负载均衡的基础策略, ...
- js轮询导致服务器瘫痪_面试官:讲一下什么是负载均衡,什么是轮询策略随机策略哈希策略...
什么是负载均衡? 先举个例子吧.以超市收银为例,假设现在只有一个窗口.一个收银员: 一般情况下,收银员平均 2 分钟服务一位顾客,10 分钟可以服务 5 位顾客:到周末高峰期时,收银员加快收银,平均 ...
最新文章
- ecside使用笔记(1)
- nodejs-模块系统
- haproxy,lvs keepalived || heartbeat,nginx对比
- 【数据分析】用于数据分析的8个SQL技术
- mysql replace into 语法_mysql Replace into与Insert update
- 关于NOR FLASH地址左右移的问题
- matlab dpsk,2DPSK调制与解调matlab(最新整理)
- 吴恩达机器学习7——支持向量机SVM
- 初学Sockets编程(四) 发送和接收数据
- 18、【易混淆概念集】第十一章2 实施定量风险分析 模拟、敏感性分析、决策树分析 风险应对策略 消极/威胁应对策略 积极/机会风险应对策略 开拓和提高的区别
- 当你第一次发送ping请求包,ARP缓存表为空时会发生什么?(详细解析全过程)
- Python xls文件和xlsx文件格式互相转换
- weblogic下java程序占用cpu过高的问题排查
- 【目标跟踪】基于matlab GUI帧差法结合卡尔曼滤波行人姿态识别【含Matlab源码 1127期】
- 简单逆向分析使用案例(2)--CrackMe_01.exe 找出密码
- Python渗透测试编程技术-拒绝服务攻击
- Python读书笔记第五章:运算符与表达式
- 《Real-Time Rendering 4th Edition》读书笔记--简单粗糙翻译 第二章 渲染管线 The Graphics Rendering Pipeline
- 大量数据转录的多线程和同步处理实现
- MongoDB的安装、配置运行 与 Robomongo的下载安装
热门文章
- 注射美容已出现滥用趋势
- Android实现应用程序的开机自启动
- 创新也能始于山寨 - 李开复对话微博Plurk创始人
- excel文件打不开怎么办_从零开始修电脑__无法打开office文件的解决方法
- 嫦娥五号轨道器成为我国首颗进入日地L1点周期轨道航天器并开展拓展试验
- 浅谈归一化对于LSTM进行时间序列预测的影响(附归一化代码)
- 降低node版本,怎么降低node版本
- 安徽大学导游系统设计---迪杰斯特拉算法实现
- 【炸雷】Elasticsearch 的 Log4j 漏洞处置策略
- 【iOS】音频播放之AVAudioPlayer,AVPlayer,AVQueuePlayer