漫画 | 什么是散列表(哈希表)?

创建与输入数组相等长度的新数组,作为直接寻址表。两数之和的期望是Target,将Target依次减输入数组的元素,得到的值和直接寻址表比较,如果寻址表存在这个值则返回;如果不存在这个值则将输入数组中的元素插入寻址表,再进行输入数组中的下一个元素。

再进一步优化可以将输入数组直接作为直接寻址表,控制对应的下标就好,代码如下:

Code:直接寻址表
class Solution {
        public int[] twoSum(int[] nums, int target) {
        for (int i = 1; i < nums.length; i++) {
            int temp = target - nums[i];
            for (int j = 0; j < i; j++) {
                if (temp == nums[j]) return new int[]{j, i};
            }
        }
        return null;
    }
}
动画:直接寻址表

数组里面每一个槽位放的是8个字节,用于一个指向外部类的引用。这个外部类可以是链表对象,也可以是红黑树对象,都可以存一个或者一个以上的元素,也可以是空链表或空树。散列表在某种意义上需要的数组空间可以比直接寻址表要少的很多。

散列函数是将所有元素的键转换为自然数,自然数的数集是{0,1,2,……}。

如果所有元素的键是正整数,最常用的方法是求模(除留余数法)。我们选择长度为素数M的数组,对于任意正整数k,计算k mod M求得余数;

如果所有元素的键是浮点数,我们将它表示为二进制数,忽略小数点再转化为十进制,然后求模;

如果所有元素的键是字符串,可以将它字符串里面的每一个字符通过ASCII码转换,并相加得到这个字符串的hash,然后求模;

如果所有元素的键是对象或者组合键(对象里面的是属性类型不定),也可以通过上面的方法混合起来。

除了线性探测法,还有二次探测还有双重探测。

线性探测法是,通过散列函数得到散列值,检查这个散列值是否被占用,如果被占用,将索引增大,到达数组结尾时折回数组的开头,直到找到没有被占用的散列值。

线性探测采用的散列函数为:

其中h`(k)是第一次通过散列函数得到的散列值。

二次探测采用的散列函数为:

双重探测采用的散列函数为:

其中

键簇,是指元素在插入数组后聚集成的一组连续的条目,决定线性探测的平均成本。

如下图所示,插入之前已经看到了两个比较长的键簇,如果待插入元素通过散列函数得到的散列值正好是这两个键簇中的第一个位置,就需要探测很多次才能找到空的位置;如果落在了两个键簇间的只有一个空位置,那就产生了更长的键簇,对线性探测的平均成本大大增加。

显然,短小的键簇才能保证较高的效率,不管是插入、查找还是删除算法。随着插入的键越来越多,较长的键簇越来越多,有可能插入一个元素就将两个很长的键簇合并。所以才有了两次探测和双重探测,可以降低这种情况出现。

动态空间处理其实就是改变数组的长度,可以设定一个构造函数,这个构造函数可以接受一个固定的容量作为参数。

M是目前散列表数组的长度,N是目前在散列表已插入元素的个数。如何扩容和缩容可以设定一个条件,如果N/M >= 上边界,即平均每个槽承载元素超过一定程度,就进行扩容;如果N/M <= 下边界,即平均每个槽承载元素降到一定程度,就进行缩容。

扩容和缩容都会创建一个新的长度M的散列表,散列函数也会因为M而改变,原来的所有元素通过新的散列函数重新散列并插入新的散列表中。

动画:动态空间处理

Java 8之前,每一个槽对应一个链表;

Java 8开始之后,当哈希冲突达到一定程度时,每一个位置槽从链表转成红黑树。

面试官很客气,一直送我到门口,我依依不舍地离开这个地方。嗯,面试官真是个好人。

我出去大门,看见一个面试者在拿着A4纸一直默读,我想那个面试官待会要面这个人吧。小伙子,你运气真好,希望你面试成功。

场景虚构,如有雷同,实属巧合

-----完结-----

喜欢本文的朋友,欢迎关注公众号 @ 算法无遗策,和我们一起学数据结构、刷算法题。


喜欢本文的朋友,欢迎关注公众号「算法无遗策」,收看更多精彩内容

原文地址:https://www.cnblogs.com/wotxdx/p/12230486.html

时间: 2024-08-07 07:33:41

漫画 | 什么是散列表(哈希表)?的相关文章

散列表(哈希表)

序言: 如果将一系列的记录按照关键字的某种函数存储,那么在查找某个数据的时候就可以直接通过关键字计算出来了,而不在需要“比较”,这样会非常高效,这就是散列技术. 所以散列技术就是:     存储位置=f(关键字)        不管是记录的存储还是查找,都用这种方法 散列技术具有很高的效率,但是使用起来有一些限制.如1个关键字对应多个记录的情况(比如在一个学校的学生中按性别查找,则对应太多的记录),此外散列技术同样不适合于范围查找和排序等操作. 一.散列函数的构造 在设计散了函数的时候主要考虑两

[BS]散列表 哈希表 Hash table

<第五章> 散 列 散列表的实现常常叫做散列(hashing).散列是一种用于以常数平均时间执行插入.删除和查找的技术. 关于散列有一个很重要的概念:散列函数.散列函数是散列的关键处之一,散列函数又是基于映射机制的一种对应关系(一般是多对一的关系). 这章可以分为5个部分:一般想法,散列函数,分离链接法,开放定址法(可分为线性探测.平方探测.双散列).再散列.可扩散列. 本文只写到前四节.即:一般想法,散列函数,分离链接法,开放定址法(可分为线性探测.平方探测.双散列)() 第五章第一节:一般

散列表之直接寻址表

散列表之直接寻址表 直接寻址表的定义 直接寻址表的操作 直接寻址表的代码实现 dataNode的定义 直接寻址表的定义 测试文件 编译运行 总结 注意: 本文中的所有代码你可以在这里: https://github.com/qeesung/algorithm/tree/master/chapter11/11-1/directAddr(这里的会及时更新) 或者这里: http://download.csdn.net/detail/ii1245712564/8793509 找到 散列表之直接寻址表

[数据结构] 散列表(哈希表)

散列表(哈希表) 比较难理解的官方定义:散列表/哈希表(Hash table),是根据关键码值(Key value)而直接进行访问的数据结构.它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. 举个例子,我们在查找中文字典时.假设我们要查找"翁weng",我们根据weng找到了对应的页码233,这个过程就是根据关键码值映射得到了表中的位置.然后我们在字典这个散列表中,根据我们刚才得到的位置 233页,直接访问了"

数据结构与算法----散列/哈希

1. 简介 散列表的实现叫散列hashing,散列用于以常数平均时间执行 插入.删除.查找,不支持排序.findMin.findMax. 查找关键字不需要 比较 在一个记录的存储位置和它的关键字之间建立映射关系:key--f(key)   这个关系就是散列函数/哈希函数.将一些记录存储在一块 连续 的存储空间,这块空间就是散列表/哈希表. 与线性表.树.图比较: 数据元素之间没有什么逻辑关系,也不能用连线图表示出来. 问题: 关键字不同,但通过散列函数计算的结果相同,即出现了冲突 collisi

HashTable-哈希表/散列表

HashTable-散列表/哈希表,是根据关键字(key)而直接访问在内存存储位置的数据结构.它通过一个关键值的函数将所需的数据映射到表中的位置来访问数据,这个映射函数叫做散列函数,存放记录的数组叫做散列表. 构造哈希表的几种方法 直接定址法--取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A.B为常数. 除留余数法--取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址.Hash(Key)= Key % P. 平方取中法

哈希表线性探测

HashTable-散列表/哈希表,是根据关键字(key)而直接访问在内存存储位置的数据结构. 它通过一个关键值的函数将所需的数据映射到表中的位置来访问数据,这个映射函数叫做散列函数,存放记录的数组叫做散列表. 哈希冲突/哈希碰撞 不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突.任意的散列函数都不能避免产生冲突. 我给大家介绍的是哈希表的线性探测,线性探测的基本思路: 1.用一个数据除以散列表的长度,余数是多少,就把这个数放在散列表下标相同

MySQL中哈希表

也称为散列表 由直接寻址表改进而来.先看直接寻址表 当关键字的全域U比较小时,直接寻址是一种简单而有效的技术.加入某应用要用到一个动态集合,其中每个元素都有一个取自全域U={0,1,...,m-1}的关键字.同时假设没有两个元素具有相同的关键字 用一个数组(即直接寻址表)T[0...m-1]表示动态集合,其中每个位置(或称槽或桶)对应全域U中的一个关键字.图5-38说明了这个问题.槽K指向集合的一个关键字为k的元素.如果该集合没有关键字k的元素,则T[k]=NULL 直接寻址存在一个很明显的问题

算法导论-散列表(Hash Table)

目录 引言 直接寻址 散列寻址 散列函数 除法散列 乘法散列 全域散列 完全散列 碰撞处理方法 链表法 开放寻址法 线性探查 二次探查 双重散列 随机散列 再散列问题 完整源码(C++) 参考资料 内容 1.引言 如果想在一个n个元素的列表中,查询元素x是否存在于列表中,首先想到的就是从头到尾遍历一遍列表,逐个进行比较,这种方法效率是Θ(n):当然,如果列表是已经排好序的话,可以采用二分查找算法进行查找,这时效率提升到Θ(logn);  本文中,我们介绍散列表(HashTable),能使查找效率