首页 > 其他分享 >哈希数据结构

哈希数据结构

时间:2023-07-17 16:47:28浏览次数:48  
标签:下标 哈希 函数 冲突 数组 数据结构 HashMap

参考链接:https://blog.csdn.net/CRMEB/article/details/120820682

1. 哈希表

哈希表,即散列表(Hash table),是根据key value而直接进行访问的数据结构。也就是说,它通过把key value映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

哈希作为一个非常常用的查找结构,它能够在O(1)的时间复杂度下进行数据查找。每次寻找的时候都对键进行计算从而得到一个数组下标值,然后通过下标拿到数组对应的数据,就能知道它是否存在于这个数组中了。

这种数据查找的数据结构就叫做哈希表,对键的计算的方法叫做哈希函数。在Java中,典型的Hash数据结构的类是HashMap。

哈希表的执行步骤:

  • 对键进行哈希计算,得到一个哈希值
  • 对哈希值进行计算得到一个数组下标
  • 通过数组下标得到数组中对应的数组

由于哈希表的查找步骤和哈希函数是恒定不变的,因此哈希表的时间复杂度为O(1)。

2. 哈希函数

哈希函数是一种提取数值特征的算法,针对不同的数据形式有不同的哈希算法,所以哈希函数并不通用,针对不同的场景有很多不同的哈希算法,比如我们常见的MD5就是一种获取文件信息摘要的哈希算法。

再比如在Java中,对于常用的数据类型,JDK实现了多种不同的hash函数。

Integer的哈希函数是直接拿到它的值,对于字符串类型则是使用了对应的算法,对于浮点类型则是使用位运算的方式进行哈希计算。针对不同的数据结构使用不同的哈希计算方法的原因是为了哈希值的均匀,哈希越均匀,说明哈希函数设计的越好,也预示的哈希冲突的减少,关于哈希冲突,将在下一节讲到。

除了计算哈希值,我们还需要计算数组的位置。计算数组的位置有很多种方法可用,我们介绍一下简单的除留余数法:

假设对“中国人”这个key进行计算,得到一个哈希值19942986,那么我们将用这个数字对数组的大小进行取余,假设我们的数组大小为11,得到这样的计算公式:

19942986 % 11 = 8

那么,我们就得出了本次哈希函数的结果为数组下标8,我们就可以把中国人这个字符放到了数组下标为8的位置上。

既然哈希值越均匀越好,那么数组下标是否也有类似的需求呢?

是有的,比如我们上面的除留余数法,在除留余数法中,数组大小的选择将深刻影响着取余结果是否均匀,所以在除留余数法中,我们一般使用质数,这也是为什么HashTable的初始化大小为11,因为11是一个质数。

3. 哈希冲突

哈希冲突指的是多个不同的键散列到了同一个数组下标位置上,案例如下:

在上图中,耳、朵、不这三个字经过散列之后的数组下标都是0,而且因为是三个不同的值,所以也不能直接在数组上覆盖,那么我们就需要有一个办法把这三个值存起来。

这里将介绍两种常用的方法:开放地址法和链地址法。

开放地址法是一种比较简单的解决冲突的方法,它的原理非常简单:

在第一个耳字已经占用下标0后,第二个朵字则向后进行寻找空余的下标,找到后将自己设置进去,所以朵字在下标1处,以此类推。

根据寻找下标的方式不同,开放地址法可以分为以下几种:

线性探测法:下标被占用之后,以步长为1依次向后寻找,上图例中我使用的就是这种方法。

二次探测法:下标被占用之后,步长为2的倍数,依次向后寻找。

伪随机探测法:下标被占用后,随机出一个数字,然后使用这个数字作为下标进行寻找,这种方法全靠天意了。

其实原理都差不多,都是在当前下标的基础上向后寻找空余的下标,不过步长不一样罢了。
链地址法俗称拉链法,就是在冲突的下标元素处维护一个链表,所有冲突的元素都依次放到这个链表上去:

在上图中,我将冲突的两个键就按照顺序放在了链表中,下次寻找时只需要查看该数组元素以及遍历这个链表即可,在Java中的HashMap中就是用了这种方法进行解决哈希冲突。

以上两种方法都有可能随着冲突的增多,导致查找效率变低,所以没有一个完美的方案可以解决哈希冲突的问题,我一般推荐使用拉链法,因为它比较简单易理解。

4. HashMap案例

前文中大量提到了HashMap,这一节就将对HashMap中的一些和上文讲述不一样的关键点进行梳理。

首先是HashMap的表容量,表容量就是这个哈希表中可以装下多少个元素。

前文中我们说,在哈希表中最好使用质数作为表的容量,并且还拿了HashTable作为举例。而在HashMap中,初始容量为16,这不仅是一个偶数还是2的倍数。HashMap之所以没有使用质数而是使用2的倍数作为它的容量,是因为它在计算数组下标时没有使用除留余数法,而是使用了位运算进行计算数组下标。

 static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

计算完哈希值之后,则是使用哈希值和数组长度进行位运算:(tab.length - 1) & hash。

5. 手写哈希表

了解上边的哈希知识之后,我们就可以自己写一个类似Hashmap的数据结构。做一个哈希表的必要条件是:

哈希函数

哈希冲突方法

 

标签:下标,哈希,函数,冲突,数组,数据结构,HashMap
From: https://www.cnblogs.com/bowenliang/p/17560509.html

相关文章

  • 数据结构
    数据结构中的基本概念  数据:任何能够输入到计算机中,能被程序处理的描述客观事物的符号  数据项:有独立含义的最小单位,也叫做数据域、域  数据元素:组成数据的、有一定意义的基本单位,也叫作节点、结点、顶点(一个数据元素是由若干项数据项组成)  数据结构:相互之间......
  • 7.17 数据结构
    线段树小白逛公园动态维护最大子段和,没啥好说的文文的摄影布置考虑清楚标记分讨合并算术天才⑨与等差数列维护区间最大最小,如果是等差数列,有了端点就可以知道整个序列了,再维护哈希值对比就可以了,突然发现我之前这个解法是乱搞,只有充分性没有必要性,只是题目没有卡正解:维护......
  • docker分布式存储之哈希槽3主3从redis集群配置+主从扩容缩容
    创建开启六台redis容器systemctlrestartdockerdockerpullredis:6.0.8根据需求下载redis的镜像版本配置3主3从开启六台redis容器分别用node-1~node-6来区分dockerrun-d--nameredis-node-1--nethost--privileged=true-v/tmp/redis/share/redis-node......
  • 数据结构小记
    线段树区间查询线段树可以维护具有结合律的信息。区间修改区间查询加上修改后应当满足的前提是我们可以维护一个封闭的集合\(\mathcal{S}\),使得任一操作\(o\in\mathcal{S}\),且\(\mathcal{S}\)对于复合封闭,即对任意\(u,v\in\mathcal{S}\),有\(u\circv\in\mathcal{S}\)......
  • 二. 基础数据结构
    二.基础数据结构0.引JSON是一个有着特殊结构的数据,为了解析JSON,需要使用编程语言将JSON的数据格式进行抽象,有助于更好地,快捷地实现JSON数据的解析.为了使解析JSON结构的性能更好,选用C语言实现JSON的数据结构的抽象,以及底层的结构的解析功能实现.1.JSON基础数......
  • 数据结构练习笔记——创建有序单链表
    创建有序单链表【问题描述】为从键盘终端输入的m个整数创建带头结点的有序单链表存储结构,使输入的数据元素在单链表中按照元素值递增有序。【输入形式】第一行:单链表中元素个数m第二行:单链表中的m个整数【输出形式】按递增有序形式输出m个整数【样例输入】513245【......
  • C语言:数据结构之单链表(四)
    本篇谈一谈单链表的改,具体操作就是找到他,然后修改元素即可,上一篇有相关代码,可以参考。改函数代码如下:voidCorrect(LinkListheader,intsite_,charletter_){LinkListq=Search_Site(header,site_);q->letter=letter_;}main函数如下:(修改第6,......
  • 数据结构之顺序表
    顺序表顺序表的定义     线性表是具有相同数据类型的n(n>=0)个数据元素的有限序列   顺序表---用顺序存储的方式实现线性表。顺序存储---把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。   如何知道一个......
  • Perl学习笔记2_标量数组哈希
    1.概述Perl是弱类型语言,变量不需要指定类型,解释器根据上下文自动选择匹配类型.Perl有三个基本的数据类型:标量($),数组(@),哈希(%).2.标量,scalar标量变量以$标记.my$a=123;#数字my$b="123";#字符串my$c=0x1F;#16进制my$d=047;#8进制my$e......
  • 数据结构 查找 红黑树查找
    1.红黑树的定义红黑树可以看作是对平衡二叉树的进一步改进。平衡二叉树的一个缺点在于插入和删除操作中为了维持平衡会消耗很大的执行代价,降低效率。红黑树的结构是在平衡二叉树的平衡标准上稍微放宽得到的。红黑树的定义:......