【数据结构】7.4 散列表的查找

news2024/11/26 5:44:35

文章目录

  • 7.4.1 散列表的基本概念
  • 7.4.2 散列函数的构造
    • 散列函数的构造方法
  • 7.4.3 处理冲突的方法
    • 1. 开地址法
      • 1.1 线性探测法
      • 1.2 二次探测法
    • 2. 链地址法
  • 7.4.4 散列表的查找
    • 散列表的查找效率分析
  • 总结

7.4.1 散列表的基本概念

  • 基本思想:根据要存储的关键字的值,来计算该存在哪里。
    • 对应关系 —— hash 函数,通过这个函数将关键字的值对应到它的存储位置。
    • Loc(i) = H(keyi)。
      在这里插入图片描述

举个例子

【例1】:

在这里插入图片描述
在这里插入图片描述

  • 这些同学们的信息,既不是按照输入顺序存的,也没有排好序按照递增或递减的方式存储。
  • 而是根据学号最后两位数,直接对应到存储位置。
    • 如果想找某位同学的信息,直接根据学号后两位去对应位置找就行了。

【例2】:

  • 根据元素序列(21,23,39,9,25,11),若规定每个元素 k 的存储地址 H(k) = k,请画出存储结构图。
    • H(k) = k:关键字的值是多少,对应的位置就是多少。
  • 按照这样的方式来存储的话,要找某一个元素就会非常方便了,直接根据给定的值去固定的位置找就行了。

在这里插入图片描述

如何查找

  • 根据散列函数:H(key) = k
    • 查找 key = 9,则访问 H(9) = 9 号地址,若内容为 9 则成功找到;
    • 若查不到,则返回一个特殊值,如空指针或空记录。

散列表的特点

  • 优点:查找效率高,时间效率可以达到 O(1)。
  • 缺点:空间效率低。

散列表的术语

  1. 散列方法(杂凑法):
    • 选取某个函数,依该函数按关键字计算元素的存储位置,并按此存放;
    • 查找时,由同一个函数对给定值 k 计算地址。将 k 与地址单元中元素关键码进行比较,来确定查找是否成功。
  2. 散列函数(杂凑函数):散列方法中使用的转换函数
  3. 散列表(杂凑表):
    • 一个有限连续的存储空间,用来存储按照散列函数计算得到相应散列地址的数据记录。
    • 通常散列表的存储空间是一个一维数组,散列地址是数组下标。

在这里插入图片描述

  1. 冲突:不同的关键码映射到同一个散列地址。
    • key1 ≠ key2,但是 H(key1) = H(key2)。值不相同,但是都住进了一间房。
    • 例:有 6 个元素的关键码分别为:(25,21,39,9,23,11)。
      • 选取关键码与元素位置间的函数为 H(k) = k % 7.
      • 地址编号从 0 - 6.。
    • 在散列查找方法中,冲突是不可避免的,只能尽可能减少。

在这里插入图片描述

  1. 同义词:具有相同函数值的多个关键字。
    • 如:上图互相冲突的值,虽然值不相同,但是函数值一样,导致了它们会呆在同一块空间内。
      在这里插入图片描述

7.4.2 散列函数的构造

使用散列表要解决两个问题

  1. 构造好的散列函数
    • 所选函数尽可能简单,以便提高转换速度;
    • 所选函数对关键码计算出的地址,应尽可能使散列地址集中致均匀分布,以减少空间浪费。
  2. 制定一个好的解决冲突的方案
    • 查找时,如果从散列函数计算出的地址中查不到关键码,则应当依据结局冲突的规则,有规律的查询其它相关单元。

构造散列函数需要考虑的因素

  1. 执行速度:即计算散列函数所需要的时间;
  2. 关键字的长度
  3. 散列表的大小:散列表越大,产生冲突的可能性越小,但是浪费空间;
  4. 关键字的分布情况:根据关键字的特点,怎样才能使他们分布的更均匀;
  5. 查找频率:让需要经常查找的元素更容易被找到。

根据元素集合的特性构造

  • 要求一:n 个数据源仅占用 n 个地址,虽然散列查找是以空间换时间,但是仍希望散列的地址空间尽量小
  • 要求二:无论用什么方式存储,目的都是尽量均匀的存放元素,以避免冲突。

散列函数的构造方法

  1. 直接定址法
  2. 数字分析法
  3. 平方取中法
  4. 折叠法
  5. 除留余数法
  6. 随机数法

直接定址法

  • Hash(key) = a * key + b(a、b为常数)
  • 优点:以关键字 key 的某个线性函数值为散列地址,不会产生冲突。
  • 缺点:要占用连续地址空间,空间效率低。

例:{100,300,500,700,800,900},
散列函数:Hash(key) = key/100(a = 1/100,b = 0)

在这里插入图片描述

除留余数法

  • Hash(key) = key % p(p 是一个常数),将余数作为数据元素的存储位置。
  • 关键:如何选取合适的 p ?
  • 技巧:假设表长为 m,取 p <= m 且为质数

例:{15, 23, 27, 38, 53, 61, 70},散列函数 Hash(key) = key % 7,7 <= 表长7,且为质数。

在这里插入图片描述

如果想反过来找某个数也是同样的方法,如:找61,61 % 7 = 5,那么就去 5 号位置找它。

7.4.3 处理冲突的方法

  1. 开放定址法(开地址法)
  2. 链地址法(拉链法)
  3. 再散列法(双散列函数法)
  4. 建立一个公共溢出区

1. 开地址法

基本思想

  • 有冲突时就去寻找下一个空的散列地址;
  • 只要散列表足够大,空的散列地址总能找到,并将数据元素存入。
    • 例如:除留余数法 Hi = (Hash(key) + di) % m,di 为增量序列。
  • 开地址法的三种方法 % 的都是表长 m ,不要和除留余数法构造散列表的 % 最大质数 p 搞混了。

常用方法

  • 线性探测法:增量序列 di 为 1,2,…m-1 的这样一个线性序列。
  • 二次探测法:增量序列 di 为 12,-12,22,-22,…,q2 的二次序列。
  • 伪随机探测法:增量序列 di 为伪随机数序列,加上一个伪随机数,将 key 随机的存储到后面的某一个位置,这个位置空着的话就存上,非空的话就继续产生一个随机数找下一块空间。

1.1 线性探测法

Hi = (Hash(key) + di) % m(1 <= i < m)

  • 其中:m 为散列表长度,di 为增量序列 1,2,…m-1,且 di = i
  • 一旦冲突,就找下一个地址,直到找到空地址存入

举个例子

关键码集合为 {47,7,29,11,16,92,22,8,3},散列表长度为 m = 11;散列函数为 Hash(key) = key % 11;拟用线性探测法来来处理冲突。

在这里插入图片描述

  1. 47 % 11 = 3,将 47 放在 3 号位置。7 % 11 = 7,将 7 放在 7 号位置。

在这里插入图片描述

  1. Hash(29) = 29 % 11 = 7,此时出现冲突,需要存到下一位置。
    • di = 1,2,3,…,m-1,由 H₁ = (Hash(29 + 1) % 11 = 8,并且散列地址 8 还空着,因此将 29 存入。
    • 让 29 存进去的时候已经做了两次运算了。

在这里插入图片描述

  1. Hash(11) = 11 % 11 = 0,且 0 还空着,将 11 存入 0号位置。Hash(16) = 16 % 11= 5,且 5 为空,将 16 存入 5号位置。Hash(92) = 92 % 11 = 4,4 空,存之。

在这里插入图片描述

  1. Hash(22) = 0,此时 22 与 0 号位置的 11 产生冲突。
    • 往后移一位 (Hash(22) + 1) % 11 = 1,存储到 1 号位置去。

在这里插入图片描述

  1. Hash(8) = 8,与 29 产生冲突,寻找下一块空置空间 9 存入。

在这里插入图片描述

  1. Hash(3) = 3,与 47 冲突,依次往后寻找闲置空间。
    • (Hash(3) + 3) % 11 = 6,di 从 1 一直加到 3 才找到一块空着的空间 6,此时将 3 存入。

在这里插入图片描述

同样,如果想要找出 3 的话,Hash(3) = 3 % 11 = 3,先从 3 号位置开始找,发现不是则依次往后找,直到比较了 4 次之后才终于找到。

平均查找长度

  • 将所有元素的比较次数相加 / 元素个数
    • 比较次数:11 要比较一次,22 比较两次,3 比较3次…

在这里插入图片描述

1.2 二次探测法

关键码集合为 {47,7,29,11,16,92,22,8,3},

  • 设:散列函数为 Hash(key) = key % 11Hi = (Hash(key) + di) % m
  • 其中:m 为散列表长度, m 要求是某个 4k + 3 的质数;di 为增量序列 12,-12,22,-22,…,q2
    • 如果当前要插入的值与当前位置产生冲突,首先要探测当前位置的下一位置,如果下一位置还是冲突,则探测当前位置的前一位置。

举个例子

在这里插入图片描述

  • 其中:

    • 黑色数字为第一次就找到空闲位置成功存进去的值。
    • 蓝色为第一次比较时与其他位置有冲突的值,它们可以直接找到下一位置作为栖息地。
  • 剩下的元素 3 就不能只通过往后移一位找到地方待了。

    • 3 号位置已经有元素了,先让 3 在当前 3 号位置上加 1 看看 4 是否有空位,4 号位置非空,此时应该移动 -1 位到 2 号位置判断时候有空位,2 号位置为空,将关键码 3 插入在此。

在这里插入图片描述

2. 链地址法

基本思想

  • 将相同散列地址的记录链成一条单链表,m 个散列地址就设置 m 个单链表,然后用一个数组将 m 个单链表的表头指针存储起来,形成一个动态的结构。

举个例子

  • 现有一组关键字为: {19,14,23,1,68,20,84,27,55,11,10,79}
  • 散列函数为:Hash(key) = key % 13
    • 这个时候我们就发现了, 有几个元素是同义词(% 13 的余数相等),如14,1,27,79,也就是说这几个元素会产生冲突。
    • 将同义词(冲突的元素)链接在同一条单链表上。
    • 将链表存储在函数值算出来的位置上,如 14,1,27,79,他们的余数都是 1,将由他们链接的链表首地址放在数组 1 号位置,其余元素同理。

在这里插入图片描述

链地址法建立散列表步骤

  • Step1:取数据元素的关键字 key,计算其散列函数值(地址)。
    • 若该地址对应的链表为空,则将该元素插入此链表;否则执行 Step2 解决冲突。
  • Step2:根据选择的冲突处理方法,计算关键字 key 的下一个存储地址。
    • 若该地址对应的链表不为空,则利用链表的前插法或后插法将该元素插入此链表。

链地址法的优点

  • 非同义词不会冲突,无聚集现象。
  • 链表上结点空间动态申请,更适合于表长不确定的情况。

7.4.4 散列表的查找

算法步骤

  1. 给定待查找的关键字 key,根据造表时设定的散列函数计算 Ho = H(key)。
  2. 若单元 Ho 为空,则所查找元素不存在。
  3. 若单元 Ho 中元素的关键字为 key,则查找成功。
  4. 否则重复以下解决冲突的过程:
    • 按处理冲突的方法,计算下一个散列地址 Hi;
    • 若单元 Hi 为空,则所查找元素不存在;
    • 若单元 Hi 中元素的关键字为 key,则查找成功。

在这里插入图片描述

举个例子

已知一组关键字(19,14,23,1,68,20,84,27,55,11,10,79)散列函数为:H(key) = key % 13,散列表长为 m = 16,假设每个记录的查找概率相等。

一、线性探测然后再散列处理冲突,即 Hi = (H(key) + di) % m

  • 第一次构造散列表是 % 小于表长的最大质数,所以是13。
  • 处理冲突的时候是要 mod 表长,所以是 % 16.

如果想要找 79 的话就需要比较 9 次才能找到。在这里插入图片描述
在这里插入图片描述

平均查找长度:所有元素的比较次数之和 / 元素个数。

  • ASL = (1 X 6 + 2 + 3 X 3 + 4 + 9)/ 12 = 2.5

二、用链地址法处理冲突

在这里插入图片描述

散列表的查找效率分析

使用平均查找长度 ASL 来衡量查找算法,ASL 取决于:

  • 散列函数
  • 处理冲突的方法
  • 散列表的装填因子 α
    • α 越大,表中记录数越多,说明表装的越慢,发生冲突的可能性就越大,查找时比较次数就越多。

在这里插入图片描述

ASL 与装填因子 α 有关!既不是严格的 O(1),也不是 O(n)。

在这里插入图片描述

总结

  • 散列表技术机油很好的平均性能,优于一些传统的技术。
  • 链地址法优于开地址法。
  • 除留余数法作散列函数优于其他类型函数。

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

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

相关文章

计算机网络-杂项

目录 1、蜂窝移动网络 2、TCP和UDP 3、5层架构 4、在浏览器中输入url地址显示主页的过程 5、TCP的基本操作 6、三次握手&#xff0c;四次挥手 6.1、三次握手&#xff1a;双方保证自己和对方都能接收和发送数据。 6.2、三次握手中&#xff0c;为什么客户机最后还要再向服…

【计算机网络】应用层体系

我们知道现代常用的计算机网络模型为5层模型&#xff0c;其中应用层是直接与我们平时常见的软件对接的最高层&#xff0c;所以先来学习应用层就显得很有必要了。其中在应用层我们需要学习网络应用程序的实现、原理并且了解网络应用程序所需要的网络服务、客户和服务器、进程和运…

DW 2023年1月Free Excel 第七次打卡 动态函数

第七章 Excel函数-动态函数 数据下载地址与参考链接&#xff1a;https://d9ty988ekq.feishu.cn/docx/Wdqld1mVroyTJmxicTTcrfXYnDd 1.FILTER函数 在工作中&#xff0c;根据指定的条件&#xff0c;将符合条件的所有记录从数据源表格式查找过来&#xff0c;一是可以用高级筛选。…

两个实用的shell命令:sed和awk用法

&#x1f34e;作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Linux系统编程 本文目录 sed的用法 sed常用场景 awk的用法 awk常用场景 我们先来看一下力扣上的shell题库中的一题&#xff1a; 实现这个功能一般来说我们会想到tail和head命令来指定打印前几行或者后几…

string的模拟实现(下)

目录 string的模拟实现下 析构函数&#xff1a; 完善函数 空对象的构造函数&#xff1a; 头插函数的一些修正&#xff1a; 构造函数的完善&#xff1a; 实现append 插入函数&#xff1a; 插入函数(字符串&#xff09; erase删除函数&#xff1a; 实现find函数&#…

【读论文】Spiking-YOLO Spiking Neural Network for Energy-Efficient Object Detection

AAAI-20 摘要 本文提出两个新方法为深度SNN提供快速、准确的信息传递&#xff1a;通道归一化和具有不平衡阈值的带符号神经元&#xff1b;本文也提出了一个基于脉冲的目标检测模型&#xff1a;Spiking-YOLO&#xff0c;并且在non-trivial datasets, PASCALVOC 和 MS COCO数据…

指针与数组

目录指针运算&#xff08;补&#xff09;指针指针指针的关系运算&#xff08;补&#xff09;指针与数组数组名二级指针指针数组指针运算&#xff08;补&#xff09; 指针指针 上一篇博客我们介绍了指针运算中的三种常见运算&#xff1a;指针整数&#xff0c;指针关系运算&…

23.1.27打卡 Codeforces Round #846 (Div. 2) A~D

https://codeforces.com/contest/1780A题给你一个长度为n的数组, 问你是否能找出三个数字, 使得这三个数字之和为奇数简单的小学数学奇偶奇偶偶偶所以我们只要找到三个奇数或者两个偶数一个奇数就好了/* ⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿…

简单复现 残差网络、Googlenet、mobilenet、SqueezeNet、ShuffleNet

1.残差网络 1&#xff09;网络结构 当对x求偏导的时候&#xff0c;F&#xff08;x&#xff09;对x求偏导的值很小的时候&#xff0c;对整体求x的偏导会接近于1 这样解决了梯度消失问题&#xff0c;我们可以对离输入很近的层进行很好的更新。 要注意的是F&#xff08;x&#…

【REACT-redux】

1. redux介绍 1.1 描述 Redux最主要是用作应用状态的管理。简言之&#xff0c;Redux用一个单独的常量状态树&#xff08;state对象&#xff09;保存这一整个应用的状态&#xff0c;这个对象不能直接被改变。当一些数据变化了&#xff0c;一个新的对象就会被创建&#xff08;使…

JDK SPI 和 Dubbo SPI

SPI &#xff08;Service Provider Interface&#xff09;&#xff0c;简单翻译就是服务提供接口&#xff0c;这里的“服务”泛指任何一个可以提供服务的功能、模块、应用或系统&#xff0c;会预留一些口子或者扩展点&#xff0c;只要按照既定的规范去开发&#xff0c;就可以动…

MES和金蝶云星空接口打通对接实战

四化智造MES&#xff08;WEB&#xff09;和金蝶云星空接口打通对接实战数据源平台:四化智造MES&#xff08;WEB&#xff09;MES建立统一平台上通过物料防错防错、流程防错、生产统计、异常处理、信息采集和全流程追溯等精益生产和精细化管理&#xff0c;帮助企业合理安排生产排…

机器视觉_HALCON_HDevelop用户指南_2.Getting Started

文章目录前言二、Getting Started2.1. 运行HDevelop2.2. 运行示例程序前言 标题本来想用“开始使用”或“快速上手”&#xff0c;不过感觉怪怪的&#xff0c;干脆就叫Getting Started吧&#xff0c;因为许多开发手册&#xff0c;开始上手的那节就叫这个名字。 本文是接上一篇…

【人工智能原理自学】LSTM网络:自然语言处理实践

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本文讲解LSTM网络&#xff1a;自然语言处理实践&#xff0c;一起卷起来叭&#xff01; 目录一、“RNN”二、编程实验一、“RNN” 上节课我们利用词嵌入把句子转化为词向量序列…

手把手本地搭建服务器笔记1

需要的下载的东西&#xff1a; vmware (百度网盘)银河麒麟镜像xshell,xftp安装vmware&#xff1a; 下载的包里有密钥&#xff0c;安装的时候就直接把密钥扔里面就好了 镜像处理&#xff1a; vmware左上角文件-新建虚拟机-典型&#xff0c;下一步 -安装程序光盘映像文件&am…

基于嵌入式物联网技术的智慧病房方案设计

文章目录前言1、要求2、系统设计3、功能模块3、系统功能模块图一、stm32控制模块原理图二、各功能模块的实现1、整个系统的基本配置2、RTOS多任务1、设计线程2、配置主函数代码3、温湿度读取模块(I2C)4、LED定时开关灯(pwm)5、按键实现报警信号6、脉搏&血氧数据读取7、UART…

【HTML】基础的入门学习

HTML 菜鸟教程 简介 一般结构&#xff1a; <!DOCTYPE html> 声明为 HTML5 文档<html> 元素是 HTML 页面的根元素<head> 元素包含了文档的元&#xff08;meta&#xff09;数据&#xff0c;如 <meta charset"utf-8"> 定义网页编码格式为 ut…

proteus仿真软件中芯片的命名规则与封装方法(详细版)

第一&#xff1a;PCB封装库命名规则 1、集成电路&#xff08;直插&#xff09; 用DIP-引脚数量尾缀来表示双列直插封装​ 尾缀有N和W两种,用来表示器件的体宽​ 为体窄的封装&#xff0c;体宽300mil,引脚间距2.54mm​ 为体宽的封装, 体宽600mil,引脚间距2.54mm​ 如&#…

11、关联数据库

文章目录11、关联数据库11.1 常规方式11.2 常规操作【尚硅谷】idea实战教程-讲师&#xff1a;宋红康 生活是属于每个人自己的感受&#xff0c;不属于任何别人的看法 11、关联数据库 11.1 常规方式 找到数据库选项&#xff1a; 添加指定数据库&#xff1a; 配置MySQL数据库…

5. 网络编程之UDP编程

1. UDP协议的特点 相比与TCP协议来说&#xff0c;UDP协议就显得相对比较简单了。 (1) UDP是无连接的   即发送数据之前不需要建立连接(当然&#xff0c;发送数据结束时也没有连接可释放)&#xff0c;因此减少了开销和发送数据之前的时延。 (2) UDP使用尽最大努力交付   即…