【Java集合类】LinkedList
2023-02-18 本文已影响0人
couthz
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通用的五种遍历方式
注意:
- ArrayList随机访问,用哪种其实影响都不是太大
- 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;
});