1.定义:数组(Array) 是一种线性表数据结构。 它用一组连续的内存空间, 来存储一组具有相同类型的数据。
概念解析:
第一是线性表(Linear List) 。 顾名思义, 线性表就是数据排成像一条线一样的结构。 每个线性表上的数据最多只有前和后两个方向。 其实除了数组, 链表、 队列、 栈等也是线性表结构。
第二个是连续的内存空间和相同类型的数据。正是因为这两个限制,它才有了一个堪称“杀手锏”的 特性:“随机访问”。但有利就有弊,这两个限制也让数组的很多操作变得非常低效,比如要想在数 组中删除、插入一个数据,为了保证连续性,就需要做大量的数据搬移工作。
在这里需要注意的是,在我们平常所说的数组适合查找,查找时间复杂度为 O(1)的说法是不对的。实际上,这种表述是不准确的。数组是适合查找操作,但是查找的时间复杂度并不为 O(1)。即便是 排好序的数组,你用二分查找,时间复杂度也是 O(logn)。所以,正确的表述应该是,数组支持随机 访问,根据下标随机访问的时间复杂度为 O(1)。
2.数组的插入与删除
2.1插入操作
正常情况下,数组的插入操作涉及到插入位置后面数组元素的移动,这样的话一般造成的平均时间复杂度为O(n),但是如果我们不关注数组元素的顺序的话,数组只是被当作一个存储数据的集合。在这种情况下,如果要将某个数组插入到第 k 个位置,为了避免大规模的数据搬移,我们还有 一个简单的办法就是,直接将第 k 位的数据搬移到数组元素的最后,把新的元素直接放入第 k 个位 置。这样的思想与快排思想有点类似。时间复杂度为O(1).
2.2删除操作
跟插入数据类似,如果我们要删除第 k 个位置的数据,为了内存的连续性,也需要搬移数据,不然中间就会出现空洞,内存就不连续了,平均时间复杂度为O(n)。实际上,在某些特殊场景下,我们并不一定非得追求数组中数据的连续性。如果我们将多次删除操作集中在一起执行,删除的效率将会得到提高。比如数组 a[10] 中存储了 8 个元素:a,b,c,d,e,f,g,h。现在,我们要依次 删除 a,b,c 三个元素。为了避免 d,e,f,g,h 这几个数据会被搬移三次,我们可以先记录下已经删除的数据。每次的删 除操作并不是真正地搬移数据,只是记录数据已经被删除。当数组没有更多空间存储数据时,我们再触发执行一次真正的删除操作,这样就大大减少了删除操作导致的数据搬移。这实际上JVM的垃圾回收算法中的清除-标记法的核心思想。
参考:极客时间《数据结构与算法之美》