开的免费网站能赚钱吗/北京企业网站推广哪家公司好
注:本文同步发布于稀土掘金。
8 散列表查找(哈希表)
8.1 定义
散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。查找时,根据这个确定的对应关系找到给定值key的映射f(key),若查找集合中存在这个记录,则必定在f(key)的位置上。
这种对应关系f称为散列函数,又称为哈希(hash)函数。采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表(Hash table),关键字对应的记录存储位置称为散列地址。
散列技术既是一种存储方法,也是一种查找方法,与线性表、树、图等结构不同,散列技术的记录之间不存在什么逻辑关系,它只与关键字有关联,因此,散列主要是面向查找的存储结构。
散列技术最适合的求解问题是查找与给定值相等的记录。但散列技术不适用于有同样关键字的情况,也不适合于范围查找。
设计一个简单、均匀、存储利用率高的散列函数是散列技术中最关键的问题,而另一个需要解决的问题是冲突——在理想情况下,每一个关键字通过散列函数计算出来的地址都是不一样的,但很多情况下会出现两个关键字key1<>key2,但f(key1)=f(key2)的情况,这种现象称为冲突(collision),key1和key2称为这个散列函数的同义词(synonym)。
8.2 散列函数的构造方法
8.2.1 直接定址法
如果我们现在要对0~100岁的人口数字统计表,那么我们对年龄这个关键字就可以直接用年龄的数字作为地址,此时f(key)=key:
如果我们现在要统计的是80后出生年份的人口数,那么我们对出生年份这个关键字可以用年份减去1980来作为地址,此时f(key)=key-1980:
也就是说,我们可以取关键字的某个线性函数值作为散列地址,即:
f ( k e y ) = a ∗ k e y + b f(key)=a * key + b f(key)=a∗key+b ( a 、 b 为常数) (a、b为常数) (a、b为常数)
这样的散列函数优点就是简单、均匀,也不会产生冲突,但问题是这需要事先知道关键字的分布情况,适合查找表较小且连续的情况。由于这样的限制,在现实应用中,此方法虽然简单,但却并不常用。
8.2.2 数字分析法
如果关键字是位数较多的数字,比如11位手机号“130xxx1234”,其中前三位是接入号,一般对应不同运营商公司的子品牌,如130是联通如意通、136是移动神州行、153是电信等;中间四位是HLR识别号,表示用户号的归属地;后四位才是真正的用户号:
若现在要存储某家公司员工登记表,如果用手机号作为关键字,那么极有可能前7位都是相同的,因此选择后面的四位成为散列地址。
如果这样的抽取工作还是容易出现冲突问题,还可以对抽取出来的数字再进行反转(如1234改成4321)、右环位移(如1234改成4123)、左环位移、甚至前现数与后两数叠加(如1234改成12+34=46)等方法。
抽取方法是使用关键字的一部分来计算散列存储位置的方法,这在散列函数中是常常用到的手段。
数字分析法通常适合处理关键字位数比较大的情况,如果事先知道关键字的分布且关键字的若干位分布比较均匀,就可以考虑使用数字分析法。
8.2.3 平方取中法
假设关键字是1234,那么它的平方就是1234*1234=1522756,再抽取中间的3位就是227,用做散列地址,而如果关键字是4321,那么它的平方就是18671041,抽取中间的3位就可以是671,也可以是710,用做散列地址。
平方取中法比较适合于不知道关键字的分布,而位数又不是很大的情况。
8.2.4 折叠法
折叠法是将关键字从左到右分割成位数相等的几部分(注意最后一部分位数不够时可以短些),然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址。
比如关键字是9876543210,散列表表长为3位,那么它会被分成“987”、“654”、“321”、“0”四部分,然后将它们叠加求和987+654+321+0=1962,然后根据散列表长3位,取后3位即962作为散列地址。
如果还不能够保证分布均匀,则可以对某些被分割成的部分进行反转再相加,例如将“987”反转成“789”,将“321”反转成“123”,再相加789+654+123+0=1566,再取后3位为566。
折叠法事先不需要知道关键字的分布,适合关键字位数较多的情况。
8.2.5 除留余数法
除留余数法是最常用的构造散列函数方法,对于散列表长为m的散列函数公式为:
$f(key) = key \mod p $ ( p < = m ) (p <= m) (p<=m)
例如,对一个有12个记录的数据,我们取p=11,得到如下散列表:
通常情况下,若散列表长度为m,则p一般定义为小于或等于m(最好接近m)的最小质数或不包含小于20质因子的合数。
8.2.6 随机数法
选择一个随机数,取关键字的随机函数值为它的散列地址,即:
f ( k e y ) = r a n d o m ( k e y ) f(key)=random(key) f(key)=random(key)
当关键字的长度不等时,采用随机数法构造散列函数是比较合适的。
8.2.7 总结
上文描述的构造散列函数的方法如下所示:
构造方法 | 描述 | 适用场景 |
---|---|---|
直接定址法 | f(key) = a * key + b (a、b为常数) | 事先知道关键字的分布情况,表较小且连续的情况 |
数学分析法 | 观察数据,找到数据中不重复或重复度较小的部分,抽取出来直接作为散列函数,或者将抽取出来的数字进行反转(如1234改成4321)、右环位移(如1234改成4123)、左环位移、甚至前现数与后两数叠加(如1234改成12+34=46)等,形成散列函数,如取电话号码中代表真正用户号的后四位作为散列函数 | 适合事先知道关键字的分布,且关键字的若干位分布比较均匀,且关键字位数比较大的情况 |
平方取中法 | 将关键字取平方,然后取中间的散列表长度数量的数字作为散列函数,例如假设关键字是1234,那么它的平方就是1234*1234=1522756,再抽取中间的3位就是227,用做散列地址,而如果关键字是4321,那么它的平方就是18671041,抽取中间的3位就可以是671,也可以是710,用做散列地址 | 适合于不知道关键字的分布,而位数又不是很大的情况 |
折叠法 | 将关键字从左到右分割成位数相等的几部分(注意最后一部分位数不够时可以短些),然后将这几部分叠加求和,并按散列表表长,取后几位作为散列地址,比如关键字是9876543210,散列表表长为3位,那么它会被分成“987”、“654”、“321”、“0”四部分,然后将它们叠加求和987+654+321+0=1962,然后根据散列表长3位,取后3位即962作为散列地址 | 事先不需要知道关键字的分布,适合关键字位数较多的情况 |
除留余数法 | f(key) = key mod p (p <= m) 若散列表长度为m,则p一般定义为小于或等于m(最好接近m)的最小质数或不包含小于20质因子的合数 | 最常用的构建散列函数的方法 |
随机数法 | f(key)=random(key) | 当关键字的长度不等时,采用随机数法构造散列函数是比较合适的 |
8.3 处理散列冲突的方法
8.3.1 开放定址法
所谓开放定址法,就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入,公式是:
f i ( k e y ) = ( f ( k e y ) + d i ) m o d m f_i(key) = (f(key) + d_i) \mod m fi(key)=(f(key)+di)modm
( d i = 1 , 2 , 3...... , m − 1 ) (d_i=1,2,3......,m-1) (di=1,2,3......,m−1)
例如,关键字集合为{12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34},表长为m12,因此公式是f(key) = key mod 12。
对于关键字{12, 67, 56, 16, 25},f(key)都不会冲突,因此直接插入:
计算key=37时,发现f(37)=37%12=1,与25所在的位置冲突,于是应用公式f(37)=(f(37)+ d 1 d_1 d1) mod 12=(1+1)%12=2%12=2,将37插入到地址2:
计算key=22时,发现f(22)=22%12=10,直接插入到地址10:
计算key=29时,f(29)=29%12=5,插入到地址5:
计算key=15时,f(15)=15%12=3,插入到地址3:
计算key=47时,f(47)=47%12=11,直接插入地址11:
计算key=48时,f(48)=48%12=0,与12所在的位置冲突,于是应用公式f(48)=(f(48)+ d 2 d_2 d2) mod 12=(0+2)%12=2%12=2,冲突,应用公式f(48)=(f(48)+ d 3 d_3 d3) mod 12=(2+3)%12=5%12=5,冲突,应用公式f(48)=(f(48)+ d 4 d_4 d4) mod 12=(5+4)%12=8%12=9,将48插入到地址9:
计算key=34时,f(34)=34%12=10,冲突,应用公式f(34)=(f(34)+ d 5 d_5 d5) mod 12=(10+5)%12=15%12=3,冲突,应用公式f(34)=(f(34)+ d 6 d_6 d6) mod 12=(3+6)%12=9%12=9,冲突,应用公式f(34)=(f(34)+ d 7 d_7 d7) mod 12=(9+7)%12=16%12=3,冲突,应用公式f(34)=(f(34)+ d 8 d_8 d8) mod 12=(3+8)%12=11%12=11,冲突,应用公式f(34)=(f(34)+ d 9 d_9 d9) mod 12=(11+9)%12=20%12=8,冲突,应用公式f(34)=(f(34)+ d 1 0 d_10 d10) mod 12=(8+10)%12=18%12=6,插入到地址6:
散列表插入结束。
代码实现比较简单:
/*** generate open addressing hash table** @param array to insert array* @return inserted array* @author Korbin* @date 2023-12-06 09:10:53**/
public int[] openAddressing(int[] array) {if (null == array || array.length <= 1) {return array;}int length = array.length;int[] result = new int[length];Set<Integer> usedAddressSet = new HashSet<>();int data = 1;for (int a : array) {int mod = a % length;if (usedAddressSet.contains(mod)) {mod = (mod + data++) % length;while (usedAddressSet.contains(mod)) {mod = (mod + data++) % length;}}usedAddressSet.add(mod);result[mod] = a;}return result;
}
8.3.2 再散列函数法
事先准备好除留余数法、直接定址法、数学分析法、平方取中法、折叠法等等,在出现冲突时,随机选择一个函数重新计算地址的方式,称为再散列函数法。
8.3.3 链地址法
链地址法的实现是,存储地址存储的是单链表,当出现冲突时,把冲突的关键字存储到链表中即可,将所有关键字为同义词的记录存储在一个单链表中的表称为同义词表。
仍以关键字集合{12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34}为例。
对于关键字{12, 67, 56, 16, 25},f(key)都不会冲突,因此直接插入:
对于关键字37,f(37)=37%12=1,与25所在的地址冲突,因此将它作为25的后继结点:
对于关键字22、29、15、47,由于没有冲突,直接插入:
对于关键字48,f(48)=48%12=0,与12所在的地址冲突,因此将它作为12的后继结点:
对于关键字34,f(34)=34%12=10,与22所在的地址冲突,因此将它作为22的后继结点:
插入结束。
单链表的结点定义,在大话数据结构-线性表中已有描述,链地址法的实现逻辑如下所示:
/*** generate link list addressing hash table** @param array to insert array* @return inserted array* @author Korbin* @date 2023-12-06 09:51:33**/
@SuppressWarnings("unchecked")
public LinkListNode<Integer>[] linkAddressing(int[] array) {if (null == array || array.length == 1) {return null;}int length = array.length;LinkListNode<Integer> firstNode = new LinkListNode<>(array[0]);LinkListNode<Integer>[] result = (LinkListNode<Integer>[]) Array.newInstance(firstNode.getClass(), length);for (int a : array) {int mod = a % length;if (null != result[mod]) {result[mod].setNext(new LinkListNode<>(a));} else {result[mod] = new LinkListNode<>(a);}}return result;
}
8.3.4 公共溢出区法
公共溢出区法即定义多个地址表,当出现冲突时,将冲突的关键字存储到溢出表中,如下所示:
可见,公共溢出区法较适用于冲突较少的关键字存储,若冲突较多,则需要定义多个溢出表,导致大量的存储浪费。
8.4 散列表查找实现
我们只针对开放定址法和链地址法两种散列表进行查找。
对于链地址法,由于关键字存储在单链表中,因此直接使用f(key)=key%m,在查找到的单链表中查询关键字是否存在即可,若存在则返回f(key),否则返回-1表示未查找到。
对于开放定址法,仍然先使用f(key)=key%m进行定位,若该地址上的关键字与要查询的关键字不同,则令f(key)=(f(key)+1)%m,继续进行查找,但也不能无限查找下去,因此使用count计数,当整个地址表被查找过一次后,停止查找。
/*** find address of key** @param addresses addresses* @param key key to find address* @return address of key* @author Korbin* @date 2023-12-06 10:24:18**/
public int findAddress(LinkListNode<Integer>[] addresses, int key) {if (null == addresses || addresses.length == 0) {return -1;}int length = addresses.length;int mod = key % length;LinkListNode<Integer> address = addresses[mod];while (null != address) {if (address.getData() == key) {return mod;}address = address.getNext();}return -1;
}/*** find address of key** @param addresses addresses* @param key key to find address* @return address of key* @author Korbin* @date 2023-12-06 10:18:19**/
public int findAddress(int[] addresses, int key) {if (null == addresses || addresses.length == 0) {return -1;}int length = addresses.length;int mod = key % length;int count = 0;while (count < 2) {if (addresses[mod] == key) {return mod;}mod = (mod + 1) % length;if (mod == 0) {// iterate from mod to mod - 1count++;}}return -1;
}
相关文章:

大话数据结构-查找-散列表查找(哈希表)
注:本文同步发布于稀土掘金。 8 散列表查找(哈希表) 8.1 定义 散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。查找时,根据这个确定的对应关系找到给…...

持续集成交付CICD:Sonarqube自动更新项目质量配置
目录 一、实验 1.Sonarqube手动自定义质量规则并指定项目 2.Sonarqube自动更新项目质量配置 一、实验 1.Sonarqube手动自定义质量规则并指定项目 (1)自定义质量规则 ①新配置 ②更多激活规则③根据需求激活相应规则④已新增配置 ⑤ 查看 &#x…...

Linux设置Docker自动创建Nginx容器脚本
文章目录 前言一、本地新建脚本二、复制本地脚本到服务器三、执行服务器脚本总结如有启发,可点赞收藏哟~ 前言 一、本地新建脚本 在本地新建nginx-generator.sh脚本文件,并保存以下内容 主要动态定义两个变量(容器名称/服务器本地文件名、端…...

技术博客:Vue中各种混淆用法汇总
技术博客:Vue中各种混淆用法汇总 摘要 本文主要介绍了在Vue中使用的一些常见混淆用法,包括new Vue()、export default {}、createApp()、Vue.component、Vue3注册全局组件、Vue.use()等,以及如何使用混淆器对代码进行加固,保护应…...

【python】Python生成GIF动图,多张图片转动态图,pillow
pip install pillow 示例代码: from PIL import Image, ImageSequence# 图片文件名列表 image_files [car.png, detected_map.png, base64_image_out.png]# 打开图片 images [Image.open(filename) for filename in image_files]# 设置输出 GIF 文件名 output_g…...

python/matlab图像去雾/去雨综述
图像去雾和去雨是计算机视觉领域的两个重要任务,旨在提高图像质量和可视化效果。本文将综述图像去雾和去雨的算法、理论以及相关项目代码示例。 一、图像去雾算法 基于暗通道先验的方法: 这是广泛应用于图像去雾的经典算法之一。该方法基于一个观察&…...

Docker+jenkins+gitlab实现持续集成
1.安装环境 服务器ip虚拟机版本192.168.5.132centos7.6192.168.5.152centos7.6 2. 安装docker 安装必要的一些系统工具 yum install -y yum-utils device-mapper-persistent-data lvm2添加软件源信息,要确保centos7能上外网 yum-config-manager --add-repo http:…...

Web前端JS如何获取 Video/Audio 视音频声道(左右声道|多声道)、视音频轨道、音频流数据
写在前面: 根据Web项目开发需求,需要在H5页面中,通过点击视频列表页中的任意视频进入视频详情页,然后根据视频的链接地址,主要是 .mp4 文件格式,在进行播放时实时的显示该视频的音频轨道情况,并…...

MySQL生成UUID并去除-
uuid()函数 uuid() 函数可以使mysql生成uuid,但是uuid中存在-,如下图: 去除uuid的- 默认生成的uuid含有-,我们可以使用replace函数替换掉-,SQL如下 select replace(uuid(),"-","") as uuid;Insert语句中使用UUID 如果…...

包与字符串
包是分类管理的需要,建立包用:package,包中类的引用import 学习使用javaAPI中的字符串类String,学会其成员方法的使用 (必看)eclipse包的分层等级结构设置 因为eclipse的包的结构默认是平行等级的,所以要手…...

【Gradle】mac环境安装Gradle及配置
官网安装说明:Gradle | Installation 由于Gradle运行依赖jvm,所以事先需要安装jdk,并确认你的jdk版本和gradle版本要求的对应关系,这个官网上有说明,但是我试了一下不太准确,供参考,链接如下&a…...

使用C语言操作kafka ---- librdkafka
1 安装librdkafka git clone https://github.com/edenhill/librdkafka.git cd librdkafka git checkout v1.7.0 ./configure make sudo make install sudo ldconfig 在librdkafka的examples目录下会有示例程序。比如consumer的启动需要下列参数 ./consumer <broker> &…...

误用STM32串口发送标志位 “USART_FLAG_TXE” “USART_FLAG_TC”造成的BUG
当你使用串口发送数据时是否出现过这样的情况: 1.发送时第一个字节丢失。 2.发送时出现莫名的字节丢失。 3.各种情况字节丢失。 1.先了解一下串口发送的流程图(手动描绘): 可以假想USART_FLAG_TXE是用于检测"弹仓"&…...

指针(三)
函数指针 定义:整型指针是指向整形的指针,数组指针式指向数组的指针,其实函数指针就是指向函数的指针。 函数指针基础: ()优先级要高于*;一个变量除去了变量名,便是它的变量类型;一个指针变量…...

labelimg遇到的标签修改问题:修改一张图像的标签时,保存后导致classes.txt改变
问题描述:修改一张图像的标签时候, classes.txt 会同步更新,导致重新生成了 classes.txt 但是这个 classes.txt 只有你现在写的那个类别名,以前的没有了。 解决:设置一个 predefined_classes.txt,内容和模…...

Spring Cloud Gateway使用和配置
Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关ÿ…...

RT-Thread 时钟管理
时钟管理 时钟是非常重要的概念,和朋友出去游玩需要约定时间,完成任务也需要花费时间,生活离不开时间。 操作系统也一样,需要通过时间来规范其任务的执行,操作系统中最小的时间单位是时钟节拍(OS Tick&…...

User: zhangflink is not allowed to impersonate zhangflink
使用hive2连接进行添加数据是报错: [08S01][1] Error while processing statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask. User: zhangflink is not allowed to impersonate zhangflink 有些文章说需要修…...

深入理解Sentinel系列-1.初识Sentinel
👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理、分布式技术原理🔥如果感觉博主的文章还不错的话ÿ…...

vue中字典的使用
1.引入字典 dicts: [order_status,product_type],2.表单中使用 select下拉 <el-form-item label"订单状态" prop"orderStatus"><el-select v-model"form.orderStatus" clearable placeholder"请输入订单状态" :disabled"…...

AWS基于x86 vs Graviton(ARM)的RDS MySQL性能对比
概述 这是一个系列。在前面,我们测试了阿里云经济版(“ARM”)与标准版的性能/价格对比;华为云x86规格与ARM(鲲鹏增强)版的性能/价格对比。现在,再来看看AWS的ARM版本的RDS情况 在2018年&#…...

ESP32 蓝牙音箱无法链接上电脑的解决:此项不起作用,请确保你的蓝牙设备仍可检测到
ESP32 被我加了放大器后通过A2DP链接手机播放一直正常,但是怎么都链接不到电脑,蓝牙设备可以被发现和配对,但是始终无法连接,显示: 此项不起作用,请确保你的蓝牙设备仍可检测到,然后再试一次 …...

会声会影2024软件还包含了视频教学以及模板素材
会声会影2024中文版是一款加拿大公司Corel发布的视频编软件。会声会影2024官方版支持视频合并、剪辑、屏幕录制、光盘制作、添加特效、字幕和配音等功能,用户可以快速上手。会声会影2024软件还包含了视频教学以及模板素材,让用户剪辑视频更加的轻松。 会…...

[Swift]RxSwift常见用法详解
RxSwift 是 ReactiveX API 的 Swift 版。它是一个基于 Swift 事件驱动的库,用于处理异步和基于事件的代码。 GitHub:https://github.com/ReactiveX/RxSwift 一、安装 首先,你需要安装 RxSwift。你可以使用 CocoaPods,Carthage 或者 Swift …...

探索鸿蒙_ArkTs开发语言
ArkTs 在正常的网页开发中,实现一个效果,需要htmlcssjs三种语言实现。 但是使用ArkTs语言,就能全部实现了。 ArkTs是基于TypeScript的,但是呢,TypeScript是基于javascript的,所以ArkTs不但能完成js的工作&a…...

案例049:基于微信小程序的校园外卖平台设计与实现
文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…...

通过提示工程释放人工智能
在快速发展的技术领域,人工智能 (AI) 处于前沿,不断重塑我们与数字系统的交互。这一演变的一个关键方面是大型语言模型 (LLM) 的开发和完善,它在从客户服务机器人到高级数据分析的各种应用中已变得不可或缺。利用这些法学硕士的潜力的核心是提…...

亚马逊云科技Serverless视频内容摘要提取方案
概述 随着GenAI的普及,视频内容摘要生成成为一个备受关注的领域。通过将视频内容转化为文本,可以探索到更广泛的应用场景,其中包括: 视频搜索与索引:将视频内容转化为文本形式,可以方便地进行搜索和索引操作…...

c语言:整数与浮点数在内存中的存储方式
整数在内存中的存储: 在计算机内存中,整数通常以二进制形式存储。计算机使用一定数量的比特(bit)来表示整数,比如32位或64位。在存储整数时,计算机使用补码形式来表示负数,而使用原码形式来表示…...

dockerdesktop 导出镜像,导入镜像
总体思路 备份时 容器 > 镜像 > 本地文件 恢复时 本地文件 > 镜像 > 容器 备份步骤 首先,把容器生成为镜像 docker commit [容器名称] [镜像名称] 示例 docker commit nginx mynginx然后,把镜像备份为本地文件,如果使用的是Docker Desktop,打包备份的文件会自动存…...