HELLO算法笔记之散列表(哈希)

news2024/11/15 8:49:58

一、哈希表

建立键 key 与值 value 之间的映射,实现高效的元素查询。输入一个key,以O(1)获取对应的value

遍历:

# 遍历哈希表
# 遍历键值对 key->value
for key, value in mapp.items():
    print(key, "->", value)
# 单独遍历键 key
for key in mapp.keys():
    print(key)
# 单独遍历值 value
for value in mapp.values():
    print(value)

知识点1、哈希函数:

将一个较大的输入空间映射到一个较小的输出空间。在哈希表中,输入空间是所有 key ,输出空间是所有桶(数组索引)。换句话说,输入一个 key ,我们可以通过哈希函数得到该 key 对应的键值对在数组中的存储位置

输入一个 key ,哈希函数的计算过程分为两步:首先,通过哈希算法 hash() 计算得到哈希值;接下来,将哈希值对桶数量(数组长度)capacity 取模,从而获取该 key 对应的数组索引 index 。

index = hash(key) % capacity

 

每个桶都放着一个键值对

buckets[index] =Pair(key, val)

知识点2、哈希冲突和扩容

存在“多个输入对应相同输出”的情况,可以通过扩容哈希表来减少哈希冲突

 类似于数组扩容,哈希表扩容需将所有键值对从原哈希表迁移至新哈希表,非常耗时。并且由于哈希表容量 capacity 改变,我们需要重新计算所有键值对的存储位置,进一步提高了扩容过程的计算开销。

「负载因子 Load Factor」是一个重要概念,其定义为哈希表的元素数量除以桶数量,为了衡量哈希冲突的严重程度,也常被作为哈希表扩容的触发条件。例如在 Java 中,当负载因子超过 0.75 时,系统会将哈希表容量扩展为原先的 2 倍。

二、哈希冲突

  1. 改良哈希表数据结构,使得哈希表可以在存在哈希冲突时正常工作
  2. 仅在必要时,即当哈希冲突比较严重时,执行扩容操作。

哈希表的结构改良方法主要包括链式地址和开放寻址。

哈希表的结构改良方法一:链式地址

将单个元素转换为链表,将键值对作为链表节点,将所有发生冲突的键值对都存储在同一链表中。每个桶都是一个列表/链表

 

  • 查询元素:输入 key ,经过哈希函数得到数组索引,即可访问链表头节点,然后遍历链表并对比 key 以查找目标键值对。
  • 添加元素:先通过哈希函数访问链表头节点,然后将节点(即键值对)添加到链表中。
  • 删除元素:根据哈希函数的结果访问链表头部,接着遍历链表以查找目标节点,并将其删除。

哈希表的结构改良方法二:开放寻址

「开放寻址 Open Addressing」不引入额外的数据结构,而是通过“多次探测”来处理哈希冲突,探测方式主要包括线性探测、平方探测、多次哈希。

 

线性探测存在以下缺陷:

  • 不能直接删除元素。删除元素会在数组内产生一个空位,查找其他元素时,该空位可能导致程序误判元素不存在。因此,需要借助一个标志位来标记已删除元素。(查找的时候是遍历整个表的,如果遇到none就会返回不存在)(开放寻址法都会有不能直接删除元素的缺陷。)
  • 容易产生聚集。数组内连续被占用位置越长,这些连续位置发生哈希冲突的可能性越大,进一步促使这一位置的“聚堆生长”,最终导致增删查改操作效率降低。

对哈希的解释:对 1 个对象进行 Hash,就可以得到这个对象的一个映射值,这个映射值其实就是 Hash 值,这值转换存到数组的某个位置中,就是放到桶中。

三、哈希算法

无论是开放寻址还是链地址法,它们只能保证哈希表可以在发生冲突时正常工作,但无法减少哈希冲突的发生

一些简单的哈希算法:

  • 加法哈希:对输入的每个字符的 ASCII 码进行相加,将得到的总和作为哈希值。
  • 乘法哈希:利用了乘法的不相关性,每轮乘以一个常数,将各个字符的 ASCII 码累积到哈希值中。
  • 异或哈希:将输入数据的每个元素通过异或操作累积到一个哈希值中。
  • 旋转哈希:将每个字符的 ASCII 码累积到一个哈希值中,每次累积之前都会对哈希值进行旋转操作。

当我们使用大质数作为模数时,可以最大化地保证哈希值的均匀分布

哈希表的 key 可以是整数、小数或字符串等数据类型。编程语言通常会为这些数据类型提供内置的哈希算法,用于计算哈希表中的桶索引。

  • 在哈希表中,我们希望哈希算法具有确定性、高效率和均匀分布的特点。在密码学中,哈希算法还应该具备抗碰撞性和雪崩效应。
  • 通常情况下,只有不可变对象是可哈希的。

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

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

相关文章

REDIS缓存穿透 击穿 雪崩

一、前言 在我们日常的开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大数据量的需求,比如一些商品抢购的情景,或者…

chatgpt赋能python:Python小数运算:解决精度问题的最佳实践

Python小数运算:解决精度问题的最佳实践 在进行小数运算时,Python是一种十分常用的语言,但在进行小数运算时,由于二进制和十进制之间的转换不完全,可能会导致一些精度问题。为了避免这些问题,让我们一起了…

推荐工具D1

Windows右键菜单管理程序: 主要功能 启用或禁用文件、文件夹、新建、发送到、打开方式、自定义文件格式、IE浏览器、WinX等右键菜单项目 对上述场景右键菜单项目进行修改名称、修改图标、导航注册表位置、导航文件位置、永久删除等操作 对上述场景右键菜单自定义添…

meethigher-基于Netty的轻量级Web框架Jooby

Spring-Web的好处是,快速上手、快速成型,且成熟稳定无Bug。 但对于个人而言,这套框架太重了。由此探寻更好的轻量Web框架Jooby! 本文源码地址meethigher/jooby-example: 基于Netty的轻量级Web框架Jooby使用示例 一、搭建项目 …

chatgpt赋能python:Python遍历指南:掌握5种常用方法实现高效遍历

Python遍历指南:掌握5种常用方法实现高效遍历 作为一种高效且易学的编程语言,Python在数据处理和分析方面常常被誉为行业标准。在Python中,遍历数据结构是处理数据的基本操作之一。它可以帮助您将大规模数据转换成可视化、文本分析、机器学习…

复杂前端组件 - 拖拽排序功能设计与实现

复杂前端组件 - 拖拽排序功能设计与实现 最终效果 原生实现原理 关于拖拽 标签的图片默认是可以拖动的(效果如上图) 然而其他的标签(div等)是不能被拖动的,鼠标点击选择后移动没有拖拽效果,需要添加属性…

dubbo源码阅读之-ExtensionLoader

dubbo源码阅读之-ExtensionLoader 概述构造方法说起extensionPostProcessors 后置处理器初始化实例策略ExtensionInjector 完成ioc 中的set注入 获取扩展点实现类getExtensionClasses 加载普通的扩展点getAdaptiveExtensionClass 加载自适应的扩展点创建Adaptive代理类 获取扩展…

算法刷题-字符串-替换空格

题目:剑指Offer 05.替换空格 力扣题目链接 请实现一个函数,把字符串 s 中的每个空格替换成"%20"。 示例 1: 输入:s “We are happy.” 输出:“We%20are%20happy.” 思路 如果想把这道题目做到极致&…

Python 3 | 菜鸟教程 (一)

目录 一、Python3 简介 二、Python 发展历史 三、Python 特点 (一)易于学习 (二)易于阅读 (三)易于维护 (四)一个广泛的标准库 (五)互动模式 &#…

【C】static关键字详解

概述 static的汉语意思是静态的,在C语言中static关键字可以用来修饰局部变量、全局变量和函数。 在这里给大家补充一个知识,我们的数据在内存中存储时,大概分为3个区域。 1.栈区:我们创建的局部变量、形参等一般就存放在这个区域…

Python3 数字(Number)与字符串 | 菜鸟教程(五)

目录 一、Python3 数字(Number) (一)Python 数字数据类型用于存储数值。 1、以下实例在变量赋值时 Number 对象将被创建: 2、您也可以使用del语句删除一些数字对象的引用。 3、您可以通过使用del语句删除单个或多个对象的引用 (…

Golang每日一练(leetDay0100) 数据流中位数、二叉树序列化

目录 295. 数据流的中位数 Find-median-from-data-stream 🌟🌟🌟 297. 二叉树的序列化与反序列化 Serialize-and-deserialize-binary-tree 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Rus…

从零开始Vue项目中使用MapboxGL开发三维地图教程(六)加载点、线、面图层以及三维面图层(白模)

目录 1、加载点图层2、加载线和面图层3、加载三维面图层(白模) 1、加载点图层 开发地图应用时,加载POI等点状数据,显示文字或者图标信息,mapbox-gl对应使用的是符号图层(symbol),下面…

Canvas.drawText 是以哪里为基线往什么方向开始画的。有什么居中方案?

0 前言 Canvas.drawText(String text, float x, float y, Paint paint) 这个方法在绘制文本时是从以什么为基线向什么地方开始绘制呢,水平方向上,可以通过设置 setTextAlign(Paint.Align.??) 来设置基线在文本左边、右边或者中间。但是垂直方向上是在哪…

三、DI 依赖注入学习总结

文章目录 一、依赖注入1.1 构造函数注入1.2 Setter 方法注入(重点掌握)1.2.1 通过 Set 注入复杂类型和集合类型数据 一、依赖注入 依赖注入(Dependency Injection,DI)是 Spring 框架的核心特性之一,也是 S…

chatgpt赋能python:Python中如何输出换行符\n

Python中如何输出换行符\n 如果你是一个Python开发者,你可能已经熟悉了多个输出Python变量的方法。但是,当你需要输出换行符’\n’时,你可能会遇到一些问题。这篇文章将介绍在Python中输出换行符的几种方法,并且告诉你哪种方法是…

13.IOC容器

IOC容器 IOC:Inversion of Control,翻译过来是反转控制 IOC思想 获取资源的传统方式:在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源,在这样的模式下开发人员往往需要知道在具体…

第12课【嵌入式常见存储器类型】ROM RAM 一次性 DDR双倍速率 Flash

目录 存储器易失性存储器RAMDRAMSDRAMDDR SDRAM SRAMDRAM/SRAM总结 非易失性存储器ROMMASK ROMOTPROMEPROMEEPROM FLASH 存储器 存储器是组成计算机的重要部分,它可以存储数据,能让计算机拥有“记忆”。目前根据断电后,存储的数据是否会丢失…

TiDB v7.1.0 版本 Resource Control体验

作者: Ming 原文来源: https://tidb.net/blog/8abfaa25 简介 近期迎来了 TiDB v7.1.0 版本,也是2023年首发的LTS(Long-Term Support Release)版本,相比于之前的 v6.5.0 LTS版本已经过去了很长时间&…

Android PagerSnapHelper改造RecyclerView为ViewPage,kotlin

Android PagerSnapHelper改造RecyclerView为ViewPage&#xff0c;kotlin <?xml version"1.0" encoding"utf-8"?> <androidx.recyclerview.widget.RecyclerView xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tool…