You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ArrayList扩容后新容量序列确认及与LinkedList的add方法效率对比问询

嘿,我来帮你把这两个问题讲清楚,先从ArrayList的扩容逻辑说起~

ArrayList扩容容量变化详解

首先,不同JDK版本里ArrayList的扩容逻辑略有差异,这可能是你看到源码里有+1操作的原因:

  • JDK 7及以后的主流实现:扩容公式是 newCapacity = oldCapacity + (oldCapacity >> 1),也就是旧容量的1.5倍(右移1位等价于除以2取整)。初始容量为10的话,扩容序列是:

    • 初始容量:10
    • 第一次扩容后:10 + 5 = 15
    • 第二次扩容后:15 + 7 = 22(15>>1是7)
    • 第三次扩容后:22 + 11 = 33
    • 第四次扩容后:33 + 16 = 49(33>>1是16)
    • 以此类推...
  • JDK 6及更早版本:扩容公式是 newCapacity = (oldCapacity * 3)/2 + 1,这里就有你疑惑的+1操作了。同样初始容量10的话,序列是:

    • 初始容量:10
    • 第一次扩容后:(10*3)/2 +1 = 15+1=16
    • 第二次扩容后:(16*3)/2 +1=24+1=25
    • 第三次扩容后:(25*3)/2 +1=37+1=38
    • 以此类推...

另外还要注意两个边界情况:

  1. 如果一次性添加大量元素,导致需要的最小容量超过1.5倍扩容后的容量,那么会直接把新容量设为最小需要的容量,不会死卡1.5倍的规则。
  2. 如果扩容后的容量超过Integer.MAX_VALUE - 8,会进一步调整为Integer.MAX_VALUE(这是为了避免数组分配时的内存溢出问题)。
大规模下ArrayList与LinkedList的add效率对比

你提到的摊还分析是对的:ArrayList的add(E e)(末尾添加)操作是**摊还O(1)**时间复杂度——虽然偶尔会触发扩容(O(n)时间),但摊分到每次add操作上,平均下来还是常数时间。

那和LinkedList比呢?

  • 从理论复杂度看,LinkedList的末尾添加也是O(1)(因为它维护了尾指针,直接在尾部挂新节点)。
  • 但实际性能上,大规模添加时ArrayList通常更快,原因有两个:
    1. 缓存友好:ArrayList是基于数组的连续内存结构,CPU缓存可以批量加载数据,缓存命中率高;而LinkedList的节点是分散在堆内存中的,缓存命中率低,频繁的内存寻址会拖慢速度。
    2. 内存开销与分配:LinkedList每个元素都要创建一个Node对象,包含前后指针和元素本身,内存开销更大,而且频繁创建对象会带来更多的GC压力;ArrayList只需要在扩容时一次性分配大块内存,平时只是填充元素。

当然,如果是在中间插入/删除操作,LinkedList的O(1)(找到节点后)会比ArrayList的O(n)(需要移动后续元素)有优势,但单纯的末尾大规模添加,ArrayList是更优的选择。

内容的提问来源于stack exchange,提问作者codecode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:56:04