ArrayList与可变长度数组

190 阅读2分钟

这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

ArrayList与可变长度数组

在一部分语言中,数组(这种情况下通常会被称作链表)可以自动改变长度。数组或者链表会随着新加入元素而增加长度。而在另一部分语言中,比如Java,数组的长度是固定的。创建数组时,长度即被确定了。

当你需要类似于数组、同时提供动态长度的数据结构时,经常会用到ArrayListArrayList是一种按需动态调整大小的数组,数据访问时间为O(1)。一种典型的实现方法是在数组存满时将其扩容两倍。每次扩容用时O(n),不过这种操作频次极少,因此均摊下来访问时间仍为O(1)

这是面试中的一个基础数据结构。无论使用何种编程语言,都要确保能够熟练运用动态数组(链表)。请注意,数据结构的名称和长度调整系数(Java当中为2)在不同语言当中会有所不同。

为什么均摊访问时间是\boldsymbol{O(1)}

假设你有一个长度为N的数组,可以倒推一下在扩容时需要复制多少元素。请注意观察当我们将数组元素个数增加到K时,数组之前的大小为其一半。所以需要复制K/2个元素。

最终扩容:复制n/2个元素

之前的扩容:复制n/4个元素

之前的扩容:复制n/8个元素

之前的扩容:复制n/16个元素

……

第二次扩容:复制2个元素

第一次扩容:复制1个元素

因此,插入N个元素总共大约需要复制N/2+N/4+N/8+\cdots+2+1次,总计刚好小于N次。

因此,插入N个元素总计用时为O(N)。平均下来每次插入操作用时为O(1),尽管某些插入操作在最坏情况下需要O(N)的时间。