对于Java集合框架的整理与理解(Arraylist和Linkedlist效率篇)

本文详细探讨了Arraylist和Linkedlist在Java集合框架中的增删查效率。Arraylist查询快,增删慢;Linkedlist查询慢,增删快。通过分析时间复杂度,得出在特定操作下,如根据下标删除中端元素,Linkedlist可能比Arraylist更耗时。同时,文章提到未考虑Arraylist的动态扩容机制时,删除操作中Linkedlist效率更高。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Arraylist与Linkedlist

众所周知,Arraylist和Linklist的区别在于:

  • Arraylist 增删慢,查询快。

  • Linkedlist 增删快,查询慢。
    但如果将Arraylist与Linkedlist进行相比较的话,这俩句话是完全正确的吗?

让我们从最开始的查询讲起。

首先是Arraylist:
  • 根据index查询的时间复杂度无疑是O(1)
  • 根据元素进行查找的速度为O(n) (也就是遍历)
Linkedlist
  • 根据index查询的时间复杂度为O(n)
注意:Linkedlist根据元素进行查找的时候不能使用for循环
(这里的n是2分之n,因为采用了2分查找,但时间复杂度只有n)
  • 根据元素进行查找的速度为O(n) (也就是遍历)
注意:Linkedlist根据元素进行查找的时候不能使用for循环,
需要使用迭代器或使用增强for(本质仍然是迭代器)

原因:

        for (int i = 0;i<linkedList.size();i++){
            linkedList.get(i);//每次都要进行一次get(i)
        }

假如linkedlist的长度为10,那么进行十次遍历的时候需要的时间为1+2+3+4+5+5+4+3+2+1 = 30
时间复杂度可以简易的计算为:
每一次操作时间复杂度都和根据index进行查询的复杂度O(n)一样
一共需要进行n次操作
总共的时间复杂度为:O(n)*O(n) = O(n2)

跟据查询来看,Arraylist明显是快于Linkedlist的

接下来我们看一下Arraylist和Linkedlist的增删操作

首先是Arraylist的增加元素:

若在不涉及Arraylist的动态扩容机制,那么实际上Arraylist的增加元素就是数组的增加元素,因此,时间复杂度为O(n)
具体来说便是:

  • 增加需要O(1)
  • 将其余数组元素往后移需要O(n)
现在是Linkedlist的增加元素:

LInklist的增加元素时间复杂度同链表,为O(1)
具体来说便是:

  • 增加需要O(1)

因此在增加这一方面,Linklist的确是要高于Arraylist的。

现在轮到删除了

首先是Arraylist的删除元素:

删除分为俩种:

第一种为根据下标删除:
删除元素分为俩个步骤,查询,删除。

Arraylist的查询为O(1),删除操作与增加操作一样,总体来说是O(n)
但具体来看的话

  • 当需要删除的元素在Arraylist的前端时,需要的时间为n+1,因为所有元素都需要往前移。
  • 需要删除的元素在在Arraylist的中间端时,需要的时间为2分之n+1,因为一半元素都需要往前移。
  • 需要删除的元素在在Arraylist的后端时,需要的时间为1+1,因为不需要前移元素。
第二种为根据元素进行删除:

与第一种相比,需要遍历与删除操作,即需要的时间分别为

  • 删除n,遍历1
  • 删除2分之n,遍历2分之n
  • 删除1,遍历n
    总体为n+1

而Linkedlist的删除元素:

删除分为俩种:

第一种为根据下标删除:
删除元素分为俩个步骤,查询,删除。

依然是分为俩个步骤,查询,删除。
Arraylist的查询为O(n),删除操作与增加操作一样,是O(1)。
现在我们依旧具体来看

  • 当需要删除的元素在Linkedlist的前端时,需要的时间为1+1,因为很快就能找到结点
  • 当需要删除的元素在Linkedlist的中间端时,需要的时间为2分之n+1,需要遍历一半才能找到结点
  • 当需要删除的元素在Linkedlist的前端时,需要的时间为1+1,因为采用的2分查找,所以元素在前端和后端的时候耗费的时间是一样的。
第二种为根据元素删除:

与第一种相比,需要遍历与删除操作,即需要的时间分别为

  • 删除1,遍历1
  • 删除1,遍历2分之n
  • 删除1,遍历n

可以看出,若根据元素进行删除,则Linkedlist总体上是比Arraylist进行删除操作要快上不少的

但如果是根据第一种下标进行删除时

在元素中间的时候:

  • Arraylist 需要挪移一半元素,以及删除一个元素
  • Linkedlist 需要查询一半元素,以及删除元素

可以将Arraylist挪移一半的时间以及Linkedlist查询一半的时间对掉
但将目光投入Linkedlist和Arraylist的删除元素时,可以发现,虽然俩者的时间复杂度都是O(1),但是实际来看:

  • Arraylist只需要将元素放入即可
  • Linkedlist还需要更改将被删除元素的前一个元素的尾结点和将被删除元素的后一个元素的前结点

在其他操作耗费的时间差不多时,Linkedlist因为删除元素的耗时较高。
导致了Linkedlist在根据下标进行删除时,删除中端及后端的元素的时间会比Arraylist多上一些。

以上计算均不涉及Arraylist的动态扩容机制,若算上动态扩容机制的话,在删除元素方面,便是Linkedlist效率较高,因为从Arraylist的源码看来:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

当Arraylist进行扩容时,使用了Arrays.copyOf进行列表的复制,因此,需要消耗更多的时间。

总结

算不上什么难点,不过的确是个容易忽略的地方,写的时候可能有些错误,有错误可以指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值