哈希结构(详解)

news2024/12/26 11:02:13

目录

哈希表

哈希表原理

散列函数

哈希冲突和处理的办法

哈希集合

哈希集合的实现 

哈希映射

哈希映射的基本操作

 哈希映射的实现


哈希表

散列表(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 = 997
    self.list_ = [list() for _ in range(self.len)] 


  def add(self, key: int) -> None:
    hash_addr = key % self.len
    if key not in self.list_[hash_addr]:
      self.list_[hash_addr].append(key)


  def remove(self, key: int) -> None:
    #求地址 散列函数都是一样的
    hash_addr = key % self.len
    if key in self.list_[hash_addr]:
      self.list_[hash_addr].remove(key)


  def contains(self, key: int) -> bool:
    hash_addr = key % self.len
    if key in self.list_[hash_addr]:
      return True
    return 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 第二个列表放value
    self.list_ = [[[],[]] for _ in range(self.len)]


  def put(self, key: int, value: int) -> None:
    hash_addr = key % self.len
    #如果key已经存在与映射中,更新value
    for i, v in enumerate(self.list_[hash_addr][0]):
      if v == key:
        self.list_[hash_addr][1][i] = value
        return
    #如果没有  
    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
    # 如果找到返回当前value
    for i, v in enumerate(self.list_[hash_addr][0]):
      if v == key:
        return self.list_[hash_addr][1][i]
    
    # 如果没有 返回-1
    return -1


  def remove(self, key: int) -> None:
    hash_addr = key % self.len
    for 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.coloradmin.cn/o/758347.html

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

相关文章

dede去掉列表推荐文档的粗体字效果的修改方法

这样看起来多么的不美观了&#xff0c;现在我们本帖教程就是去掉列表这个粗体字效果。 DedeCMSv5.6具体操纵方法如下&#xff1a; 找到 /include/arc.listview.class.php 打开找到743 - 746 行下列代码&#xff1a; if(ereg(c,$row[flag])) {$row[title] "<b>"…

2023.7.15排序算法合集

排序算法合集 一、概述二、排序算法1.冒泡排序2.插入排序3.选择排序4.快速排序5.归并排序6.计数排序 三、完整源码 一、概述 排序算法是计算机科学中的一类常见算法&#xff0c;用于将一组数据按照特定的顺序进行排列&#xff1b;排序算法的应用非常广泛&#xff0c;涉及到数据…

代码随想录第三十九天||● 62.不同路径 ● 63. 不同路径 II

● 62.不同路径 这道题注意&#xff1a;初始化不仅是可以初始化一个值&#xff0c;也可以初始化整个一行或者一列值 这道题递推公式好想&#xff0c;就是初始化不太好想 机器人从(0 , 0) 位置出发&#xff0c;到(m - 1, n - 1)终点。 按照动规五部曲来分析&#xff1a; 确…

用 pesq 给 torchaudio 读取的音频数据打分

用torchaudio读取的音频文件&#xff0c;在输入pesq之前需要进行格式处理与转换。 import torchaudio from pesq import pesq# 读取音频文件 audio_clean, src torchaudio.load(./audio/NOIZEUS/clean/sp01.wav) audio_0dB, sr0 torchaudio.load(./audio/NOIZEUS/bable/0dB/…

算法:动态规划

目录 &#x1f349;什么是动态规划&#xff1f; 1&#xff09;题目解析&#xff0c;&#xff08;我们以第N个泰波那契数来进行举例&#xff09; 2&#xff09;解读算法原理 &#x1f349;第N个泰波那契数的代码编写 &#x1f349;空间优化 &#x1f349;什么是动态规划&am…

全国青少年信息素养大赛参赛练习题2

海龟画图: 漂亮的螺旋线 import turtle as tt.bgcolor("black") n=6 colors = [red, green, blue, yellow,orange,purple]for x in range(160):t.pencolor(colors[x%6])t.forward(x*5/n+x)t.left(360/n+1)t.width(x*n/200) t.up() t.left(-90) t.forward(50) t.d…

什么是番茄工作法?

基本概念 番茄工作法是由弗朗西斯科西里洛于1992年创立的一种相对于GTD更微观的时间管理方法&#xff0c;旨在帮助使用者尽可能保持专注以及创造力&#xff0c;从而更快地完成工作并减少心理疲劳。 使用番茄工作法&#xff0c;首先要选择一个待完成的任务&#xff0c;然后将番茄…

5.2 Python高级特性之---切片迭代

一、 切片 一般用于提取指定区间内的内容&#xff0c;常用于&#xff1a;str、list、tuple等类型的的局部变量&#xff0c;如下为具体案例1、 【列表切片】 res_list [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]1&#xff09; 无步长: …

Redis的数据淘汰策略了解吗?

面试官&#xff1a;Redis数据淘汰策略了解吗&#xff1f; 我&#xff1a;知道。嗯~~ 当Redis中的内存不够用时&#xff0c;此时再向Redis中添加新的key&#xff0c;Redis就会按照某种规则将内存中的数据删除掉。这种数据的删除规则被称为内存的淘汰策略。 面试官&#xff1a;…

【机器学习】吴恩达课程1-Introduction

一、机器学习 1. 定义 计算机程序从经验E中学习&#xff0c;解决某一任务T&#xff0c;进行某一性能P&#xff0c;通过P测定在T上的表现因经验E而提高。 2. 例子 跳棋程序 E&#xff1a;程序自身下的上万盘棋局 T&#xff1a;下跳棋 P&#xff1a;与新对手下跳棋时赢的概…

深度强化学习经验回放(Experience Replay Buffer)的三点高性能修改建议:随机采样、减少保存的数据量、简化计算等

高性能的 ReplayBuffer 应该满足以下三点: 随机采样 random sample 的速度要快,尽可能加快读取速度(最为重要)减少保存的数据量,增加吞吐效率(对分布式而言重要)保存能简化计算的变量(对特定算法而言重要)为了达成以上要求,我建议做出以下修改: 把 Replay Buffer 的…

【从零到Offer】反射那些事

什么是反射&#xff1f; ​ 反射简单来说&#xff0c;就是在代码运行期间&#xff0c;通过动态指定任意一个类&#xff0c;从而构建对象&#xff0c;并了解该类的成员变量和方法&#xff0c;甚至可以调用任意一个对象的属性和方法。以String对象为例子&#xff0c;传统构造方式…

Go语言开发者的Apache Arrow使用指南:数据操作

在前面的Arrow系列文章中&#xff0c;我们介绍了Arrow的基础数据类型[1]以及高级数据类型[2]&#xff0c;这让我们具备了在内存中建立起一个immutable数据集的能力。但这并非我们的目标&#xff0c;我们最终是要对建立起来的数据集进行查询和分析等操作(manipulation)的。 在这…

RecycleView闪屏问题(java和ktolin解决)

问题案例&#xff1a;图库搜索界面点击空格&#xff0c;图片会闪烁两次显示 复现概率 通过布局看是通过RecycleView加载的&#xff0c;通过打印log并无异常闪烁是 notifyDataSetChange 造成的。由于适配器不知道整个数据集中的哪些内容已经存在&#xff0c;在重新匹配 ViewHol…

vscode remote-ssh配置

使用vscode的插件remote-ssh进行linux的远程控制。 在vscode上安装完remote-ssh插件后&#xff0c;还需要安装openssh-client。 openssh-client安装 先win R打开cmd&#xff0c;输入ssh&#xff0c;查看是否已经安装了。 如果没有安装&#xff0c;用管理员权限打开powershe…

LabVIEW将彩色图像转换到灰度图像

LabVIEW将彩色图像转换到灰度图像 在LabVIEW中使用许多图像处理工具的必要步骤之一是将其从彩色转换为单色。介绍一个开发的应用程序&#xff0c;用于基于LabVIEW软件环境&#xff0c;在所有支持的色彩空间&#xff08;RGB、HSI、HSV和HSL&#xff09;中自动将彩色图像转换为灰…

Shi-Tomas角点检测、亚像素级别角点位置优化、ORB特征点、特征点匹配、RANSAC优化特征点匹配、相机模型与投影

目录 1、Shi-Tomas角点检测 2、亚像素级别角点位置优化 3、ORB特征点 4、特征点匹配 5、RANSAC优化特征点匹配 6、相机模型与投影 1、Shi-Tomas角点检测 //Shi-Tomas角点检测 int test1() {Mat img imread("F:/testMap/lena.png");if (!img.data){cout <<…

Python结巴中文分词笔记

&#x1f4da; jieba库基本介绍 &#x1f310; jieba库概述 Jieba是一个流行的中文分词库&#xff0c;它能够将中文文本切分成词语&#xff0c;并对每个词语进行词性标注。中文分词是自然语言处理的重要步骤之一&#xff0c;它对于文本挖掘、信息检索、情感分析等任务具有重要…

2023年Java最新面试题

由【后端面试题宝典】提供 和 equals 的区别是什么&#xff1f; 对于基本类型&#xff0c;比较的是值&#xff1b;对于引用类型&#xff0c;比较的是地址&#xff1b;equals不能用于基本类型的比较&#xff1b;如果没有重写equals&#xff0c;equals就相当于&#xff1b;如果重…