哈希结构(详解)

目录

哈希表

哈希表原理

散列函数

哈希冲突和处理的办法

哈希集合

哈希集合的实现 

哈希映射

哈希映射的基本操作

 哈希映射的实现


哈希表

散列表(Hash table,也叫哈希表),是根据关键码值(Key)而直接进行访问的数据结构

也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度

这个映射函数叫做哈希函数,存放记录的数组叫做哈希表。

通俗的例子是,为了查找电话簿中某人的号码,可以创建一个按照人名首字母顺序排列的表,在首字母为W的表中查找“王”姓的电话号码,显然比直接查找就要快得多。这里使用人名作为关键字

哈希表原理

image-20220829000517170

h(key) = key % size

若关键字为n,则其值存放在f(n)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数,按这个思想建立的表为散列表

对不同的关键字可能得到同一散列地址,即n1 ≠ n2,而f(n1)==f(n2),这种现象称为冲突。具有相同函数值的关键字对该散列函数来说称做同义词

在设计哈希表的时候,最需要注意两个基本因素:一个是散列函数的编写,一个是键冲突解决算法

散列函数

一般的线性表,树中,记录在结构中的相对位置是随机的,即和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的比较。这一类查找方法建立在“比较“的基础上,查找的效率依赖于查找过程中所进行的比较次数。 理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。

哈希表中元素的位置是由哈希函数确定的。将数据元素的关键字n作为自变量,通过一定的函数关系计算出的值,即为该元素的存储地址。在这推荐使用除留余数法 hash(k) = k mod p

  • 直接定址法
  • 数字分析法
  • 平方取中法
  • 折叠法
  • 随机数法
  • 除留余数数法

哈希冲突和处理的办法

在哈希表中,不同的关键字值对应到同一个存储位置的现象。即关键字n1 ≠ n2,但f(n1)= f(n2)。均匀的哈希函数可以减少冲突,但不能避免冲突。发生冲突后,必须解决;也即必须寻找下一个可用地址。

  1. 单独链表法(最常用的解决哈希冲突的算法)

    将具有同一散列地址的记录存储在一条线性链表中。例,除留余数法中,设关键字为 (18,14,01,68,27,55,79),除数为13。散列地址为 (5,1,1,3,1,3,1),

  2. 开放定址法 hash(key)+n mod len(table)

    1. n为冲突的次数,线性探测
    2. n值为冲突次数的平方,平方探测
  3. 双散列

    image-20220831152933390

  4. 再散列

    image-20220831153432916

  5. 建立一个公共溢出区

哈希集合

def add(self, key: int) -> None: # 向哈希集合插入值key
def remove(self, key: int) -> None: # 将给定值key从哈希集合中删除
def contains(self, key: int) -> bool: #返回哈希集合中是否存在这个值key

哈希集合的实现 

class MyHashSet:def __init__(self):# 由于我们使用整数除法作为哈希函数,为了尽可能避免冲突,应当将长度取为一个质数self.len = 997self.list_ = [list() for _ in range(self.len)] def add(self, key: int) -> None:hash_addr = key % self.lenif key not in self.list_[hash_addr]:self.list_[hash_addr].append(key)def remove(self, key: int) -> None:#求地址 散列函数都是一样的hash_addr = key % self.lenif key in self.list_[hash_addr]:self.list_[hash_addr].remove(key)def contains(self, key: int) -> bool:hash_addr = key % self.lenif key in self.list_[hash_addr]:return Truereturn False# Your MyHashSet object will be instantiated and called as such
# obj = MyHashSet()
# obj.add(key)
# obj.remove(key)
# param_3 = obj.contains(key)

定义一个名为`MyHashSet`的类,实现了基本的哈希集合操作。

**构造函数`__init__(self)`**:
- 初始化了一个长度为997的列表`self.list_`,列表中的每个元素都是一个空列表,用于存储哈希集合中的元素。

**`add(self, key: int) -> None`方法**:
- 接收一个整数`key`作为输入。
- 计算`key`的哈希地址`hash_addr`,使用整数除法取余数来实现哈希函数。
- 如果`key`不在`self.list_[hash_addr]`中,则将`key`添加到`self.list_[hash_addr]`中。

**`remove(self, key: int) -> None`方法**:
- 接收一个整数`key`作为输入。
- 计算`key`的哈希地址`hash_addr`。
- 如果`key`在`self.list_[hash_addr]`中,则从`self.list_[hash_addr]`中移除`key`。

**`contains(self, key: int) -> bool`方法**:
- 接收一个整数`key`作为输入。
- 计算`key`的哈希地址`hash_addr`。
- 如果`key`在`self.list_[hash_addr]`中,则返回`True`,否则返回`False`。

总结:该类通过使用哈希函数将元素存储在列表中的特定位置来实现哈希集合的基本操作。使用哈希地址来查找、添加和移除元素,以提高操作的效率。

哈希映射

hash_map被称为映射。该容器中只能存放不重复的对象。 存放的是键值对,我们可以通过键(key)来找到对应的值(value)

image-20220912144244618

哈希映射的基本操作

def __init__(self) -> None: # 用空映射初始化对象
def put(key:int, value:int) -> None: # 向 HashMap 插入一个键值对 (key, value) 。如果 key 已经存在于映射中,则更新其对应的值 value 。
def get(key:int) -> None: # 返回特定的 key 所映射的 value ;如果映射中不包含 key 的映射,返回 -1 。
def remove(key) -> None: # 如果映射中存在 key 的映射,则移除 key 和它所对应的 value

 哈希映射的实现

class MyHashMap:def __init__(self):self.len = 997# 存放的键值对,第一个列表放key 第二个列表放valueself.list_ = [[[],[]] for _ in range(self.len)]def put(self, key: int, value: int) -> None:hash_addr = key % self.len#如果key已经存在与映射中,更新valuefor i, v in enumerate(self.list_[hash_addr][0]):if v == key:self.list_[hash_addr][1][i] = valuereturn#如果没有  self.list_[hash_addr][0].append(key)self.list_[hash_addr][1].append(value)def get(self, key: int) -> int:hash_addr = key % self.len# 如果找到返回当前valuefor i, v in enumerate(self.list_[hash_addr][0]):if v == key:return self.list_[hash_addr][1][i]# 如果没有 返回-1return -1def remove(self, key: int) -> None:hash_addr = key % self.lenfor i, v in enumerate(self.list_[hash_addr][0]):if v == key:self.list_[hash_addr][0].pop(i)self.list_[hash_addr][1].pop(i)# Your MyHashMap object will be instantiated and called as such:
# obj = MyHashMap()
# obj.put(key,value)
# param_2 = obj.get(key)
# obj.remove(key)

定义一个名为`MyHashMap`的类,实现了基本的哈希映射操作。

**构造函数`__init__(self)`**:
- 初始化了一个长度为997的列表`self.list_`,列表中的每个元素都是一个包含两个空列表的列表。
- 第一个子列表用于存储键(key),第二个子列表用于存储对应的值(value)。

**`put(self, key: int, value: int) -> None`方法**:
- 接收一个整数`key`和一个整数`value`作为输入。
- 计算`key`的哈希地址`hash_addr`,使用整数除法取余数来实现哈希函数。
- 如果`key`已经存在于映射中,则更新对应的`value`。
- 如果`key`不存在于映射中,则将`key`和对应的`value`添加到`self.list_[hash_addr]`中的两个子列表中。

**`get(self, key: int) -> int`方法**:
- 接收一个整数`key`作为输入。
- 计算`key`的哈希地址`hash_addr`。
- 遍历`self.list_[hash_addr]`中的键列表,找到与`key`相等的键,并返回对应的值。
- 如果找不到相等的键,则返回-1。

**`remove(self, key: int) -> None`方法**:
- 接收一个整数`key`作为输入。
- 计算`key`的哈希地址`hash_addr`。
- 遍历`self.list_[hash_addr]`中的键列表,找到与`key`相等的键,并从键列表和值列表中删除对应的键值对。

总结:该类使用哈希函数将键值对存储在列表中的特定位置,通过哈希地址进行快速查找和操作。当插入或获取键值对时,通过计算哈希地址来定位存储位置,以提高操作的效率。如果键已经存在于映射中,则更新对应的值;如果键不存在,则将键值对添加到映射中。可以通过键获取对应的值,并且可以删除指定的键值对。

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

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

相关文章

1、QT新建工程

本章内容:本章建立一个简单的QT工程,并且对工程目录进行重新管理,再进行windows端打包部署,方便开发 一、建立工程 创建windows UI应用程序工程 到此,工程就已经建立完毕能正常运行了… 二、工程目录重新管…

lvs + keepalived

Keepalived及其工作原理 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器(MASTER)和备份服务器(BACKUP)两种角色的服务器&#x…

ES(1)简介和安装

文章目录 简介倒排索引 安装 简介 ES是面向文档型数据库,一条数据在这里就是一个文档。 和关系型数据库大致关系如下: ES7.x中废除掉Type(表)的概念 倒排索引 要知道什么是倒排索引,就要先知道什么是正排索引 idcontent100…

Django 分布式路由

简介: Django中,主路由配置文件(urls.py)可以不处理用户具体路由,主路由的配置文件可以配置成做请求的分发(分布式请求处理,分发到子路由而不是具体的视图函数)。具体的请求可以由各自的应用来处理。 步骤…

(vue)整个页面添加背景视频

(vue)整个页面添加背景视频 App.vue <template><div id"app" :class"[platform]"><video src"./assets/images/top/bg-video-711.mp4" autoplay muted loop class"bg"></video><router-view /></di…

校园网WiFi IPv6免流上网

ipv6的介绍 IPv6是国际协议的最新版本&#xff0c;用它来取代IPv4主要是为了解决IPv4网络地址枯竭的问题&#xff0c;也在其他很多方面对IPv4有所改进&#xff0c;比如网络的速度和安全性。 IPv4是一个32位的地址&#xff0c;随着用户的增加在2011年国家报道说IPv4的网络地址即…

QT开发技巧之嵌入式linux QT的QCombobox显示空白的问题

1.问题 开发平台&#xff1a;imx6ull qt版本&#xff1a;5.12.9 在嵌入式linux上运行的qt&#xff0c;QCombobox显示空白&#xff0c;不能显示其中的文本内容 2.解决办法 选中QCombobox&#xff0c;在属性栏中将foucsPolicy由WheelFocus改成NoFocus就好了

Spring Boot集成ElasticsearchRepository

Spring Boot集成ElasticsearchRepository 在上文springboot操作elasticsearch(简易版&#xff09;中&#xff0c;我们使用了elasticsearchRestTemplate操作索引及数据&#xff0c;本文主要是介绍elasic媲美数据库连接框架hibernate的数仓ElasticsearchRepository 在本文中&…

scrapy ---分布式爬虫

导模块 pip install scrapy-redis 原来scrapy的Scheduler维护的是本机的任务队列&#xff08;待爬取的地址&#xff09;本机的去重队列&#xff08;放在集合中&#xff09;---》在本机内存中 如果把scrapy项目&#xff0c;部署到多台机器上&#xff0c;多台机器爬取的内容是重…

Win10电脑开机PIN码怎么取消?

有的用户稀里糊涂的设置了PIN码之后&#xff0c;在开机时发现多了个PIN码&#xff0c;但又不知道电脑PIN码是什么意思&#xff0c;也不清楚开机PIN码怎么取消。您可以通过阅读以下内容&#xff0c;以了解什么是PIN以及如何取消PIN码。 PIN码是一种快捷登录密码方式&#xff0c;…

云计算的学习(六)

六、云计算的发展趋势 1.云计算相关领域介绍 1.1物联网 物联网来源于互联网&#xff0c;是万物互联的结果&#xff0c;是人和物、物和物之间产生通信和交互。 物联网主要技术&#xff1a; RFID技术&#xff08;射频识别技术&#xff09;传感器技术嵌入式系统技术 1.2大数据…

OpenCV - 图片增加透明通道,图片合并透明通道

1 为图像增加透明通道 一般人像抠图相关的AI模型会输出一个Mask图&#xff0c;这个Mask图就是我们需要的可以将人物抠出来的Alpha通道信息&#xff0c;我们需要将这个Mask图附加到原始图片上&#xff0c;从BGR图片转成BGRA图片或者从RGB图片转成RGBA图片。 如果使用OpenCV进行…

Matplotlib.pyplot接口汇总

Matplotlib 中的 pyplot 模块是一个类似命令风格的函数集合&#xff0c;这使得 Matplotlib 的工作模式和 MATLAB 相似。 pyplot 模块提供了可以用来绘图的各种函数&#xff0c;比如创建一个画布&#xff0c;在画布中创建一个绘图区域&#xff0c;或是在绘图区域添加一些线、标签…

win系统电脑在线打开sketch文件的方法

自Sketch诞生以来&#xff0c;只有Mac版本。Windows计算机如何在线打开Sketch文件&#xff1f; 即时设计已经解决了你遇到的大部分问题&#xff0c;不占用内存也是免费的。 您可以使用此软件直接在线打开Sketch文件&#xff0c;完整预览并导出CSS、SVG、PNG等&#xff0c;还具…

【工具推荐】企业微信、企业飞书接口调用工具

github地址: GitHub - fasnow/idebug: 企业微信、企业飞书接口调用工具。 简介 企业微信、企业飞书接口调用工具。 使用方法 wechat模块 使用use wechat 选择模块。 首先设置corpid和corpsecret&#xff0c;如有需要可以设置代理&#xff0c;之后再执行run命令。 导出通信…

微信小程序设置底部导航栏

微信小程序设置底部导航栏 1、前言2、图标准备3、小程序tabbar设置 1、前言 我们先来看下效果图&#xff1a; 注意&#xff1a; 导航栏数量最多5个&#xff0c;最少两个。 2、图标准备 阿里图标库 http://www.iconfont.cn/collections/show/29 我们进入该网站&#xff0c;选…

在SpringBoot中对RabbitMQ三种使用方式

基于API的方式 1.使用AmqpAdmin定制消息发送组件 Autowiredprivate AmqpAdmin amqpAdmin;Testpublic void amqpAdmin(){//1.定义fanout类型的交换器amqpAdmin.declareExchange(new FanoutExchange("fanout_exchange"));//2.定义两个默认持久化队列,分别处理email和sm…

云事业群CTO线技术晋升考核机试题-分布式专题-F 分布式服务链路动态追踪

2023年&#xff08;Q3财年&#xff09;技术部门CTO线技术人员晋升考核机试题 分布式篇-F 分布式服务链路动态追踪 *参考答案* 出题人&#xff1a;湖北TL田超凡答案制定&#xff1a;湖北TL田超凡 *****试卷启用前绝密**** 1 分布式服务链路动态追踪产生的背景 答&#xff…

MySQL的约束类型、数据库操作、数据表操作大全(简述)

目录 一.数据库的操作语法 二.MySQL数据库约束 三.数据类型 四.数据表操作 作者简介&#xff1a; tq02&#xff0c;一个想成为编程高手的梦中人作者主页&#xff1a; tq02的博客_CSDN博客-C语言,Java,Java数据结构领域博主学习专栏&#xff1a; &#x1f3a5; MySQL基础 …

Python 列表 insert()函数使用详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 insert函数使用详解 1、插入的位置1.1、正数索引1.2、负数索引 2、插入对象 ins…