和我一起学习前端算法 ——数据结构☞数组

254 阅读5分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」。

本来想取名为《前端算法入门》的,但是又担心自己水平不够把大家带沟里了,所以此系列文章就改名为和我一起学习前端算法

昨天肝到 11点😹,终于将空间复杂度讲完了,今天来讲讲 js 中的数据结构。

数组

你依稀知道的数组

在计算机科学中,数组数据结构(英语:array data structure),简称数组(英语:Array),是由相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储。利用元素的索引(index)可以计算出该元素对应的存储地址。

也就是说:数组(array)是一种线性表数据结构,它用一组连续的内存空间来存储一组具有相同类型的数据。

数组设计之初是在形式上依赖内存分配而成的,所以必须在使用前预先请求空间。这使得数组有以下特性:

  1. 请求空间以后大小固定,不能再改变(数据溢出问题);
  2. 在内存中有空间连续性的表现,中间不会存在其他程序需要调用的数据,为此数组的专用内存空间;
  3. 在旧式编程语言中(如有中端语言之称的C),程序不会对数组的操作做下界判断,也就有潜在的越界操作的风险(比如会把数据写在运行中程序需要调用的核心部分的内存上)。

因为简单数组强烈倚赖电脑硬件之内存,所以不适用于现代的程序设计。欲使用可变大小、硬件无关性的数据类型,Java等程序设计语言均提供了更高级的数据结构:ArrayListVector动态数组

但是,我们(前端)天天用的数组和上面说的却有点不一样😥。

JS 中的数组

说起 JS 中的数组,有两眼一抹黑的:数组不就是数组,还什么 JS 数组 😶

有知道一点的:我知道我知道,JS 数组就是对象,只不过有一个 length 属性 <( ̄▽ ̄)> 哇哈哈…

其实 “JS 数组就是对象” 这个认知在很久之前是对的,在 JS 刚出来的时候,早期的 JS 引擎的确就是这样实现的。但是时代在进步,JS引擎也在不断优化,现代 JS 引擎已经有很大进步了。

how-do-javascript-arrays-work-under-the-hood

在JS中,使用的 JS 引擎不同,对数组的实现也可能不同。下面以大家耳熟能详的 V8 为例,讲一下数组是如何实现的:

  • 如果是纯整数数组,那么背后实现为 C++ 的整型数组
  • 如果是纯数字数组,且数字中出现了小数,那么背后的实现为 C++ 的双精度浮点型数组
  • 尽管JS中没有真正意义上的数字类型(不会吧,你不会还不知道这个吧?如果你还不知道这点,建议看看 你知道但不完全知道的 ECMAScript 位运算 了解一下),但是 V8 还是会使纯数字数组操作更快,占用内存更有效率。
  • 如果数组中出现了对象,那么背后的实现为 指针数组
  • 如果背后实现的数组已经满了,然后再去调用 push 方法添加元素。会重新申请一个新的,更大长度的数组,然后将旧数组的元素复制过去,然后将需要添加的元素添加进去。这种实现方式有点像是 Java 中的 ArrayList 或者 C++ 中的 vector。(你根本不关心 V8 在背后做了多少工作,你只关心你的机械键盘够不够响(/ □ ))

上面讲的都是密集数组,如果数组是稀疏数组,那么情况又会不一样了。

  • 如果这个数组是个稀疏数组,但是又没有那么稀疏,也就是说 “洞“ 不是很多,那么背后的实现还是一个数组,并且用空值来填充那些 “洞” 。
  • 如果这个数组太尼玛稀疏了,中间隔了个太平洋,那背后就不会使用数组来实现了。将会使用 dictionary/hashtable 来实现,这样一来对数据的访问或者遍历都会比其他情况来的慢一点。

当然,以上的具体实现可能随着 V8 版本的不同会发生改变,但是由于 JS 的弱类型原因,数组的实现肯定还是会分各种情况的,基本思想是不会变的:V8 会尽量按操作最快的实现方式来,如果实在不行,才会退化成普通对象的方式。

有兴趣浓厚的大佬可以查看 builtins-array 的最新实现

总之,V8 会尽量尝试按通常意义上的数组的实现方式来,如果实在不行,才会退化成 dictionary/hashtable 的方式,就很银杏化。

上面那些花里胡哨的知识有什么用?

那上面说了那么多花里胡哨的知识,又有什么用呢?

emmm.....

好像是没有什么用😓,你要是能感觉到明显的差异那 V8 大法岂不是不灵了

老乡别走啊,你再听我狡辩几句:

  • 如果你需要追求数组的极致查找速度,那尽量使用纯数字数组,因为这样的数组才够纯(☄⊙ω⊙)☄
  • 如果你虽然使用的数组,然后由于某些原因又不想改成用对象,而又需要做很多的删除、插入操作,那么你可以试一下将这个数组搞稀疏😁
  • 我编不下去了m(_ _;;m

结语

没想到天天用的数组还藏了这么多弯弯绕绕,真的是涨知识了、

了解完了数组,接下来再了解一些经常用到的概念,下一篇将简单介绍一下链表。

本文为系列文章,将和大家一起逐步的学习前端算法相关知识。

系列所有文章都将收录在 专栏 里方便大家查看,大家可以关注我或者收藏本专栏。