再看最后一眼青春的星空

灿烂火光就像盛夏的烟火

欢送挣扎万年文明的巅峰

我们啊

将变星辰永远飘在黑暗宇宙

这个男人来自三体

Tirion

导航

通过 JS 理解 HashMap

HashMap 即哈希表,也叫散列表,是根据关键码值 key -> value 而直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录,有点类似于数组,并且能在O(1)(冲突情况另算)下查找到元素。

在 JS 中,我们最常使用的对象其实就是哈希表的实现。如:

const o = {
      name: 'Jay',
      age: 30
};

我们可以通过 o.name 直接获取其值,那么怎么就能通过一个字段名就能获取到它的值呢,内部实现是怎样的呢?
其实哈希表也是数组结构,对象的 key 会通过一个散列函数,计算出一个数值,将这个数值作为数组下标进行存放。我们在获取对象的某个字段的值时,也会使用同样的散列函数进行计算,然后从数组中取值。而从数组中取值的时间复杂度就是 \(O_1\)
当然,这个散列函数有多种实现方式,但是通常都有个问题,不同的 key 通过散列函数计算后会得到相同的一个数值。这时就需要解决此冲突。

解决冲突的时候常用的方式就是拉链法:

可以看出,存储到数组中的元素是一个链表结构,链表中的 data 的数据结构我们可以用类似 { key: 'name', value: 'Jay' } 这样的对象结构进行保存,当出现冲突时就往对应索引中的链表上继续往后添加即可。获取数据时计算出索引后也是遍历其对应的链表,判断元素中的 key 与查找的 key 是否相同,找到相同的则返回。

上面使用链表是因为静态语言中链表具有不用指定长度,方便增删等优点。而我们用 JS 来描述,则链表也可以描述成一个数组,即拉链法可以描述成一个二维数组:

如图所示,数组中每个元素的值也是一个数组,假如对象中 key 为 xx 和 yy 通过散列函数计算后的值都为2,则都存放于数组中索引为2的二维数组中;取 yy 的值时先通过散列函数计算后得到索引为2,再从索引2的数组中进行遍历,判断 key 是否为 yy,是则取出其 value。

思考:JS 中我们可以通过 o.a.b 这样的方式取值,那是否就说明了当哈希表中 value 值为对象的时候,还会创建一个哈希表?即 value 值也会是一个指针指向另一个哈希表,JS 来表示也就是一个四维数组了?

posted on 2021-01-11 15:37  Tirion  阅读(851)  评论(0编辑  收藏  举报

The Man from 3body