“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第2天,点击查看活动详情”
认识数组
数组是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
线性表:就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。除了数组,链表、队列、栈等都是线性表结构。
连续的内存空间和相同类型的数据:因为要保证连续的内存空间,因此也就导致了数组的很多操作变得非常低效,比如要在数组中删除、插入一个数据,为了保证连续性,就需要做大量的数据搬移工具。
用插入这个操作来举个例子。假设数组的长度为n,如果我们将一个数据插入到数组中第k个位置。为了把第k个位置空出来,给新的数据,我们需要将第k-n这部分的数据都顺序地往后顺移。如果在数组的末尾插入,就不需要移动数据,其数据复杂度就是O(1)。如果是在开头插入数据,所有的元素都需要依次往后移动,其数据复杂度为O(n)。所以算起来的平均时间复杂度为O(n)。
时间复杂度这里不做延伸,可以查看相关的文章。
图例示意:
几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构,数组通常情况下用于存储一系列相同数据类型的值。
在js中,也可以在数组中保存不同类型的值,但不建议这么做,不符合最佳实践。
为什么使用数组
有这样一个场景:统计一个班级所有学生的名字,用变量来实现
var name1 = '张三';
var name2 = '李四';
var name3 = '王五';
...
显然这不是一个很好的方法,如果学生很多我们会声明很多的变量,并且如果我们需要在这么多学生中做一些筛选也会很麻烦,这种情况下,我们一般都是用数组来解决。
var students = ['张三', '李四', '王五'];
数组的特点
数组有一个杀手级的特性就是:随机访问,它是如何实现的呢?
随机访问的实现:
我们来举个例子:我们先声明一个长度为5的Number类型的数组var ary = [1, 2, 3, 4, 5]。我们用图来展示下内存的存储情况。
首先计算机会给数组分配了一个连续的内存空间1000~1019,其中内存的首地址是base_addr=1000。
计算机会给每个内存单元分配一个地址,计算机通过地址来访问内存的数据。这样当计算机要随机访问数组中的某个元素时,它首先会利用下面的寻址公式,计算出要访问元素的地址来,这个公式就依赖了数组的连续的内存空间及相同类型的数据这个特点。
ary[i].addr = base_addr + i * data_size
其中data_size代表数组中每个元素的大小。因为是连续内存且知道每个单元内存大小,这样我们就可以直接根据这个公式得到要访问的元素地址。
JS中的数组
在js中的数组,主要就是API的调用,js本身对数组的封装已经很完善了。也不需要人工手动扩容,js本身就已经支持了。 在JS中,数组的一些操作方法
- 添加元素
- 删除元素
- 任意位置添加元素/删除元素
- 数组的各种迭代方法
- 数组的合并方法
- reduce方法
- 其他操作方法
具体的方法不是本篇的重点,所以这里就不展开。
相对于JS来说,在一些语言中提供的数组就比较偏底层的。比如Java中的数组。
- 其提供的数组结构中,不能存放不同的数据类型,必须在里面存放相同的数据类型,因此在Java中封装数据时。先封装一个基本类型的数组,然后数组里面是一个Object类型,因为只要是Object类型,其他类型都是继承自Object类型,这时也就可以把其他数据类型放进来。那如何限制数据类型呢,这时我们可以利用泛型来限制。由于Java提供的数组类型比较底层,因此,其本身提供了一个ArrayList类型,这我们存放不同的数据类型,并且也可以通过泛型去限制。
- 数组的内存容量不会自动扩容,需要手动的进行扩容操作。也就是说,我们在定义一个数组时,就要预先指定内存大小,因为需要分配连续的内存空间。如果我们申请了一个大小为5的数组,当第6个数据需要存储到数组时,就需要分配一块更大的空间,将原来的数据复制过去,然后再将新的数据插入。因此,在不支持动态扩容的语言中,我们最好在申请的时候一步到位,否则数据的搬运非常消耗时间。
总结
本篇文章我们学习了数组,当然这是我自己的一些学习记录,还是会存在很多我理解不深或忽略的地方,后续有了新的体会,或读者有好的建议在继续补充。
数组是我们开发过程中,使用非常频繁的数据结构,因为几乎任何项目都会存在列表形式的展示,所以我们还是必须要了解其一些相关原理与特点。经过上文的介绍,我们也知道了数组的一些特点。
优点:其随机访问的特点,可以让我们很方便的根据下标访问数据 缺点:就是对数据的插入或删除操作性能就比较低下,为了保持其连续性,需要做大量的数据迁移
因此根据这些特点,我们在做开发时可以有选择的使用。当然除非数据量很大的情况,我们都是可以用数组来做增删的。