【Java集合类】LinkedList

LinkedList的内部结构

LinkedList底层的实现是一个双向链表(非循环),每个节点包含了前驱和后继节点的引用。

并且,LinkedList包含指向链表头部和尾部的引用first和last

LinkedList内部节点类如下:

private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

与ArrayList的比较

访问比较

这里指的就是get方法

public E get(int index)

显然,ArrayList的下标随机访问比LinkedList的顺序访问快得多

ArrayList的get方法的时间复杂度为O(1)

LinkedList的为O(n)。

插入比较

对于LinkedList和ArrayList来说,都有尾部插入和指定位置插入两种方法

public void add(int index) //尾部插入
public void add(int index, E element) //指定位置插入

而LinkedList由于没有dummy node,所以头部和尾部的插入逻辑和指定位置插入的逻辑不同,还需要单独拆分出两个方法

public void addFirst(E e)
public void addLast(E e)

接下来比较一下不同位置插入的平均时间复杂度(或者说假设list中已经有一定量的元素,不考虑空list这种极端情况)

头部插入

LinkedList更快

LinkedList:O(1),损耗主要是创建Node,修改引用

ArrayList:O(n),需要利用copy操作移动元素

尾部插入

ArrayList更快

两者的插入都是O(1) (LinkedList有last引用)

但ArrayList只是隔段时间会扩容(特别是数据量大的时候,扩容频率更低)

LinkedList每次插入,创建新Node都会有消耗

随机位置插入(按下标位置)

ArrayList更快

这个可以用代码示例测试一下,基本上list规模越大,ArrayList插入的速度越快

猜测,LinkedList寻找插入位置,要比ArrayList插入之后的copy损耗更大

删除操作

删除操作其实可以类比插入操作(头部删除、尾部删除、随机位置删除)

只不过删除操作还会有**删除指定元素,**这种操作LinkedList是更快的,因为ArrayList每次删除都要进行元素迁移

public boolean remove(Object o)//删除指定元素

基本使用-初始化

以下是一些常用的初始化方法

@Test
public void test_init() {
    // 初始化方式;普通方式
    LinkedList<String> list01 = new LinkedList<String>();
    list01.add("a");
    list01.add("b");
    list01.add("c");
    System.out.println(list01);

    // 初始化方式;内部类
    LinkedList<String> list03 = new LinkedList<String>(){
        {add("a");add("b");add("c");}
    };
    System.out.println(list03);
    
    // 初始化方式;Arrays.asList
    LinkedList<String> list02 = new LinkedList<String>(Arrays.asList("a", "b", "c"));
    System.out.println(list02);
   
    // 初始化方式;Collections.nCopies,快速生成10个0的list
    LinkedList<Integer> list04 = new LinkedList<Integer>(Collections.nCopies(10, 0));
    System.out.println(list04);
}

基本使用-ArrayList和LinkedList通用的五种遍历方式

注意:

  1. ArrayList随机访问,用哪种其实影响都不是太大
  2. LinkedList,数据量大的清况下,适合iterator和foreach(本质还是iterator),因为如果直接用for循环(或者增强for),每次都得从链表头部重新开始找位置;而迭代器有cursor引用记录上次遍历的位置
//1.普通
for (int i = 0; i < list.size(); i++) {
    xx += list.get(i);
}
//2.增强for
for (Integer itr : list) {
    xx += itr;
}

//3.迭代器
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
    Integer next = iterator.next();
    xx += next;
}
//4.forEach
list.forEach(integer -> {
    xx += integer;
});

//5.流
list.stream().forEach(integer -> {
    xx += integer;
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值