首页 > 编程语言 >小白学数据结构和算法: 哈希数据结构实现原理

小白学数据结构和算法: 哈希数据结构实现原理

时间:2023-10-24 11:05:37浏览次数:31  
标签:函数 步骤 插入 小白学 哈希 表中 数据结构 我们

小白学数据结构和算法: 哈希数据结构实现原理_hash

使用哈希函数计算哈希值的复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

哈希问题

如果我们考虑上面的例子,我们使用的哈希函数是字母的总和,但是如果我们仔细检查哈希函数,那么问题可以很容易地可视化,对于不同的字符串,哈希函数开始生成相同的哈希值。 

例如:{“ab”,“ba”}具有相同的哈希值,字符串{“cd”,“be”}也生成相同的哈希值等。这称为冲突,它会在搜索中产生问题、值的插入、删除和更新。 

什么是碰撞?

散列过程为大密钥生成较小的数字,因此两个密钥有可能产生相同的值。新插入的键映射到已占用的键的情况,必须使用某种碰撞处理技术来处理。

小白学数据结构和算法: 哈希数据结构实现原理_数据结构_02

什么是哈希中的碰撞

如何处理碰撞?

处理碰撞主要有两种方法: 

  1. 单独链接:
  2. 开放寻址: 

小白学数据结构和算法: 哈希数据结构实现原理_程序员_03

碰撞解决技术

1)单独链接

其思想是使散列表的每个单元指向具有相同散列函数值的记录的链表。链接很简单,但需要表外的额外内存。

示例:我们给定了一个哈希函数,我们必须使用单独的链接方法在哈希表中插入一些元素以实现冲突解决技术。

Hash function = key % 5, 
Elements = 12, 15, 22, 25 and 37.

让我们逐步看看如何解决上述问题:

  • 步骤1:首先绘制一个空的哈希表,根据提供的哈希函数,哈希值的可能范围为0到4。
     

小白学数据结构和算法: 哈希数据结构实现原理_数据结构_04

哈希表

  • 步骤2:现在将哈希表中的所有键一一插入。第一个插入的key是12,映射到桶号2,通过哈希函数12%5=2计算得到。

小白学数据结构和算法: 哈希数据结构实现原理_数据结构_05

插入12

  • 步骤3:现在下一个键是22。它将映射到桶号2,因为22%5=2。但存储桶 2 已经被键 12 占用。

小白学数据结构和算法: 哈希数据结构实现原理_数据结构_06

插入22

  • 步骤 4:下一个键是 15。它将映射到槽号 0,因为 15%5=0。

小白学数据结构和算法: 哈希数据结构实现原理_算法_07

插入15

  • 步骤5:现在下一个键是25。它的桶号将是25%5=0。但是桶 0 已经被键 25 占用。因此单独的链接方法将通过创建到桶 0 的链表来再次处理冲突。

小白学数据结构和算法: 哈希数据结构实现原理_数据结构_08

插入25

因此,以这种方式,使用单独链接方法作为冲突解决技术。

2)开放寻址

在开放寻址中,所有元素都存储在哈希表本身中。每个表条目包含一条记录或 NIL。查找元素时,我们会逐个检查表槽,直到找到所需元素或者明确该元素不在表中。

2.a) 线性探测

在线性探测中,从哈希的原始位置开始顺序搜索哈希表。如果我们得到的位置已被占用,那么我们检查下一个位置。 

算法步骤:

  1. 计算哈希键。即键=数据%大小
  2. 检查hashTable[key]是否为空
  • 直接通过hashTable[key] = data存储值
  1. 如果哈希索引已经有一些值那么
  1. 使用key = (key+1) % size 检查下一个索引
  1. 检查下一个索引是否可用 hashTable[key] 然后存储该值。否则尝试下一个索引。
  2. 重复上述过程,直到找到空间。

示例:让我们考虑一个简单的哈希函数“key mod 5”,要插入的键序列是 50、70、76、85、93。 

  • 步骤1:首先绘制一个空的哈希表,根据提供的哈希函数,哈希值的可能范围为0到4。

小白学数据结构和算法: 哈希数据结构实现原理_hash_09

哈希表

  • 步骤2:现在将哈希表中的所有键一一插入。第一个键是 50。它将映射到槽号 0,因为 50%5=0。因此将其插入插槽号 0 中。

小白学数据结构和算法: 哈希数据结构实现原理_算法_10

将 50 插入哈希表

  • 步骤3:下一个键是70。它将映射到槽号0,因为70%5=0,但50已经在槽号0处,所以,搜索下一个空槽并将其插入。

小白学数据结构和算法: 哈希数据结构实现原理_数据结构_11

将 70 插入哈希表

  • 步骤 4:下一个键是 76。它将映射到插槽编号 1,因为 76%5=1,但 70 已经位于插槽编号 1,因此,搜索下一个空插槽并将其插入。

小白学数据结构和算法: 哈希数据结构实现原理_数据结构_12

将 76 插入哈希表

  • 步骤5:下一个键是93,它将映射到槽号3,因为93%5=3,所以将其插入槽号3。

小白学数据结构和算法: 哈希数据结构实现原理_python_13

将 93 插入哈希表

2.b) 二次探测

二次探测是计算机编程中的一种开放寻址方案,用于解决哈希表中的哈希冲突。二次探测的操作方式是获取原始哈希索引并添加任意二次多项式的连续值,直到找到空槽。

使用二次探测的示例序列是:

H + 1 2H + 2 2H + 3 2H + 4 2 ………………。H + k 2

该方法也称为中方法,因为在该方法中,我们在第 i 次迭代中查找第 i 个探针(槽),并且 i = 0, 1, ... 的值。。。n – 1。我们总是从原始哈希位置开始。如果只有该位置被占用,那么我们检查其他插槽。

令 hash(x) 为使用哈希函数计算的槽索引,n 为哈希表的大小。

如果槽 hash(x) % n 已满,那么我们尝试 (hash(x) + 1 2 ) % n。
如果 (hash(x) + 1 2 ) % n 也满了,那么我们尝试 (hash(x) + 2 2 ) % n。
如果 (hash(x) + 2 2 ) % n 也满了,那么我们尝试 (hash(x) + 3 2 ) % n。将对i
的所有值重复此过程,直到找到空槽为止

示例:让我们考虑表大小 = 7,哈希函数为 Hash(x) = x % 7 ,冲突解决策略为 f(i) = i 2。插入 = 22、30 和 50

  • 步骤1:创建一个大小为7的表。

小白学数据结构和算法: 哈希数据结构实现原理_算法_14

哈希表

  • 步骤 2 – 插入 22 和 30
  • Hash(22) = 22 % 7 = 1,由于索引 1 处的单元格为空,因此我们可以轻松地在槽 1 处插入 22。
  • Hash(30) = 30 % 7 = 2,由于索引 2 处的单元格为空,因此我们可以轻松地在槽 2 处插入 30。 

小白学数据结构和算法: 哈希数据结构实现原理_算法_15

将键 22 和 30 插入哈希表中

  • 第 3 步:插入 50
  • 哈希值(50) = 50 % 7 = 1 
  • 在我们的哈希表中,槽 1 已经被占用。因此,我们将搜索槽 1+1 2,即 1+1 = 2, 
  • 再次发现插槽 2 被占用,因此我们将搜索单元格 1+2 2,即 1+4 = 5, 
  • 现在,单元格 5 未被占用,因此我们将 50 放入槽 5 中。

小白学数据结构和算法: 哈希数据结构实现原理_程序员_16

在哈希表中插入键 50

2.c) 双重哈希

双散列是开放寻址散列表中的一种冲突解决技术。双散列利用两个散列函数, 

  • 第一个哈希函数是h1(k),它获取密钥并给出哈希表上的位置。但如果新位置未被占用或空着,那么我们可以轻松放置钥匙。 
  • 但如果位置被占用(冲突),我们将使用辅助哈希函数h2(k)与第一个哈希函数h1(k)结合来查找哈希表上的新位置。 

这种哈希函数的组合具有以下形式 

h(k, i) = (h1(k) + i * h2(k)) % n

在哪里 

  • i 是一个非负整数,表示碰撞次数,
  • k = 正在散列的元素/键
  • n = 哈希表大小。

双哈希算法的复杂度: 

时间复杂度:O(n)

示例:将键 27, 43, 692, 72 插入大小为 7 的哈希表中。其中第一个哈希函数是h1(k) = k mod 7,第二个哈希函数是h2(k) = 1 + (k模 5)

  • 第 1 步:插入 27
  • 27 % 7 = 6,位置 6 为空,因此将 27 插入到 6 插槽中。

小白学数据结构和算法: 哈希数据结构实现原理_算法_17

在哈希表中插入键 27

  • 第 2 步:插入 43
  • 43 % 7 = 1,位置 1 为空,因此将 43 插入 1 个槽中。

小白学数据结构和算法: 哈希数据结构实现原理_程序员_18

在哈希表中插入键 43

  • 步骤 3:插入 692
  • 692 % 7 = 6,但位置 6 已被占用,这是一次冲突
  • 所以我们需要使用双重哈希来解决这种冲突。
h new = [h1(692) + i * (h2(692)] % 7 
= [6 + 1 * (1 + 692 % 5)] % 7 
= 9 % 7 
= 2

现在,由于 2 是一个空槽,
所以我们可以将 692 插入第二个插槽。

小白学数据结构和算法: 哈希数据结构实现原理_python_19

在哈希表中插入键 692

  • 第 4 步:插入 72
  • 72 % 7 = 2,但位置 2 已被占用,这是一次冲突。 
  • 所以我们需要使用双重哈希来解决这种冲突。
h new = [h1(72) + i * (h2(72)] % 7 
= [2 + 1 * (1 + 72 % 5)] % 7 
= 5 % 7 
= 5,

现在,因为 5 是一个空槽,
所以我们可以将 72 插入到第 5 个槽中。

小白学数据结构和算法: 哈希数据结构实现原理_hash_20

在哈希表中插入键 72

哈希中的负载因子是什么意思?

哈希表的负载因子可以定义为哈希表包含的项数除以哈希表的大小。负载因子是当我们想要重新哈希以前的哈希函数或想要向现有哈希表添加更多元素时使用的决定性参数。

它帮助我们确定哈希函数的效率,即它告诉我们正在使用的哈希函数是否在哈希表中均匀分布键。

负载因子=哈希表中的元素总数/哈希表的大小

什么是重新哈希?

顾名思义,重新哈希意味着再次哈希。基本上,当负载因子增加到超过其预定义值(负载因子的默认值为 0.75)时,复杂性就会增加。因此,为了克服这个问题,数组的大小增加(加倍),所有值再次散列并存储在新的双倍大小的数组中,以保持低负载因子和低复杂性。

哈希数据结构的应用

  • 哈希在数据库中用于索引。
  • 哈希用于基于磁盘的数据结构。
  • 在Python等一些编程语言中,JavaScript哈希用于实现对象。 

哈希数据结构的实时应用

  • 哈希用于缓存映射以快速访问数据。
  • 哈希可用于密码验证。
  • 哈希在密码学中用作消息摘要。
  • 用于字符串中模式匹配的 Rabin-Karp 算法。 
  • 计算字符串中不同子串的数量。 

哈希数据结构的优点

  • 哈希提供比其他数据结构更好的同步。
  • 哈希表比搜索树或其他数据结构更有效
  • 哈希为搜索、插入和删除操作提供平均恒定的时间。

哈希数据结构的缺点

  • 当冲突较多时,哈希的效率很低。
  • 对于大量可能的键,实际上无法避免哈希冲突。
  • 哈希不允许空值。 

算法:计算给定总和的元素有哪些?

给定一个包含N 个整数的数组和一个整数K,任务是找到数组中总和等于K的整数对的数量。

例子:  

输入: 
输出: 
解释:和为 6 的对是 (1, 5) 和 (7, -1)。

输入: arr[] = {1, 5, 7, -1, 5}, K = 6
输出: 
解释:和为 6 的对是 (1, 5), (7, -1) & (1, 5) 。         


输入: 
输出: 
解释:和为 2 的对为 (1, 1), (1, 1), (1, 1), (1, 1), (1, 1)。

输入: 
 
( 10 , 1), (10, 1), (10, 1), (12, -1), (10, 1), (10, 1), (10, 1), (7, 4), (6, 5)。

Python 解法:

# Python 3实现的简单方法 # 查找给定和的对数。# 返回 arr [0.n-1] # 中的对数,其中 sum 等于‘ sum’
def getPairsCount(arr, n, K):

	count = 0 # 

	# 考虑所有可能的配对
	# 并检查它们的和
	for i in range(0, n):
		for j in range(i + 1, n):
			if arr[i] + arr[j] == K:
				count += 1

	return count


# 驱动器功能
arr = [1, 5, 7, -1]
n = len(arr)
K = 6
print("Count of pairs is",	getPairsCount(arr, n, K))

PHP 解法:

<?php
// PHP实现简单的方法
// 用于找到给定和的对数。

// 返回arr[0..n-1]中和为'sum'的对数。
function getPairsCount($arr, $n, $sum)
{
// 初始化结果
	$count = 0; 
// 考虑所有可能的配对
// 并检查它们的和
	for ($i = 0; $i < $n; $i++)
		for ($j = $i + 1; $j < $n; $j++)
			if ($arr[$i] + $arr[$j] == $sum)
				$count++;

	return $count;
}


$arr = array(1, 5, 7, -1, 5) ;
$n = sizeof($arr);
$sum = 6;
echo "Count of pairs is ", getPairsCount($arr, $n, $sum);

?>

标签:函数,步骤,插入,小白学,哈希,表中,数据结构,我们
From: https://blog.51cto.com/demo007x/8001574

相关文章

  • 小白学算法-数据结构和算法教程: 使用开放寻址线性探测实现自己的哈希表
    Java中使用链接实现哈希表所有数据结构都有其自身的特点,例如,当需要快速搜索元素(在log(n)中)时,会使用BST。当需要在恒定时间内获取最小或最大元素时,使用堆或优先级队列。类似地,哈希表用于在恒定时间内获取、添加和删除元素。在继续实施方面之前,任何人都必须清楚哈希表的工作原理。因此......
  • 数据结构之数组(Java)
    一:概述什么是数组呢?数组对应的英文名为array,是有限个相同类型所组成的集合,数组中的每一个变量被称为元素。数组是最为简单、最为常用的数据结构。举例说明:元素31254972索引01234567正如军队里的士兵存在编号一样,数组中的每一个元素也有着自己的小标,这......
  • Codeforces Round 905 (Div. 2) C. You Are So Beautiful(数据结构)
    CodeforcesRound905(Div.2)C.YouAreSoBeautiful定义:设数组abcd子数组定义:从原数组砍去前面若干元素,后边若干元素,剩余的数组。如:bc、ab子序列定义:从原数组删除若干元素,剩余元素拼凑一起,组成的数组。如:ac、bd思路:作为结果的连续子数组,如果他为[\(a_l\),……,\(a_......
  • 【数据结构】Splay 树
    SplaySplay树(伸展树),是平衡树的一种,而且可以维护序列,进行一些序列操作。有些序列操作功能甚至是线段树实现不了的(经典的区间翻转)。维护集合时,Splay的中序遍历单调递增,而维护序列时,Splay的中序遍历是维护的序列。Splay通过均摊(势能分析)来保证复杂度正确,单次插入,删除,查找操作......
  • C语言使用哈希表
    C语言本身是不提供哈希表的。而LeetCode上面有包含一个哈希头文件,github上面也有。是uthash头文件。这个库全部函数都是用宏实现的。以实现全部数据类型。以下是别的博客对这个库的使用介绍:https://zhuanlan.zhihu.com/p/340692819。当然,也可以直接去看github上的ut......
  • Set 和 Map 数据结构
    Set基本用法ES6提供了新的数据结构Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。Set本身是一个构造函数,用来生成Set数据结构。consts=newSet();[2,3,5,4,5,2,2].forEach(x=>s.add(x));for(letiofs){console.log(i);}//2354上面代码通......
  • 飞码LowCode前端技术系列(一):数据结构设计
    简介飞码是京东科技研发的低代码产品,可使营销运营域下web页面快速搭建。飞码是单web页面搭建工具,从创建页面到监测再到投产的一站式解决方案。会通过七篇文章介绍飞码,分别是:(1)背景与数据结构设计,(2)如何便捷配置出页面-1,(3)如何便捷配置出页面-2,(4)如何便捷配置出页面-3,(5)如何便捷配置出......
  • 小白学Python - 使用Python的文件共享应用程序
    使用Python的文件共享应用程序计算机网络 是一个重要的主题,要理解这些概念,需要实际应用这些概念。在这篇特别的文章中,我们将了解如何使用Python制作一个简单的文件共享  Web服务器是理解URL(网址)和HTTP(用于查看网页的协议)的软件。Python有几个包,它们是模块的集合。它有几个内......
  • 小白学Python - 使用 Python 的 OpenCV 绘制矩形并提取对象
    使用Python的OpenCV绘制矩形并提取对象OpenCV是一个开源计算机视觉和机器学习软件库。可以在它的帮助下完成各种图像处理操作,例如操纵图像和应用大量滤镜。它广泛用于对象检测、人脸检测和其他图像处理任务。让我们看看如何使用OpenCV在图像上绘制矩形并提取对象。编写代码#......
  • 小白学Python - 在 Python 中使用 TensorFlow 进行面部口罩检测
    在Python中使用TensorFlow进行面部口罩检测我们将使用此Python脚本来训练口罩检测器并查看结果。鉴于训练有素的COVID-19口罩检测器,我们将继续实现另外两个Python脚本,用于:检测图像中的COVID-19口罩检测实时视频流中的口罩口罩检测系统流程图 为了训练自定义口罩检测器......