前言
之前的内容中,我们分析总结了List集合及实现类ArrayList源码,并对数组扩容原理进行深度解析。本节内容主要学习总结接口List的另一个重要实现类LinkedList。先看一下LinkedList的UML类图:
- LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
- LinkedList 实现 List 接口,能对它进行队列操作。
LinkedList是一个实现了List接口和Deque接口的双端链表。
LinkedList底层的链表结构使它支持高效的插入和删除操作,另外它实现了Deque接口,使得LinkedList类也具有队列的特性。
LinkedList不是线程安全的,如果想使LinkedList变成线程安全的,可以调用静态类Collections类中的synchronizedList方法:
List<Object> linkedList = Collections.synchronizedList(new LinkedList<>());
LinkedList类的内部结构分析
来看一下LinkedList类的内部私有类Node:
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;
}
}
这个类就代表双端链表的节点Node,有三个属性:前驱节点、本节点值、后继节点。
LinedList类Demo
【1】无参构造方法
/**
* Constructs an empty list.
*/
public LinkedList() {
}
【2】按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
举个栗子:
package com.hl.magic.items.day11.collection.list;
import org.junit.Before;
import org.junit.Test;
import java.util.Iterator;
import java.util.LinkedList;
/**
* 链表LinkedList
* List接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。
* 除了实现 List 接口外,LinkedList类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。
* 这些操作允许将链接列表用作堆栈、队列或双端队列。
* <p>
* 链表LinkedList实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。
* <p>
* <p>
* 【1】LinkedList特点
* 线程不同步,线程不安全
* 增删的速度快,查询的速度慢
* <p>
* 【3】LinkedList集合存储的数据结构是链表结构,提供了大量的首尾操作的方法。
* void addFirst(E e);
* void addLast(E e);
*
* E getFirst();
* E getLast();
*
* E removeFirst();
* E removeLast();
*
* @author administrator
* @date 2020/09/25 15:13
*/
public class LinkedListBaseTest {
private LinkedList<Integer> linkedList;
/**
* LinkedList的基本操作
*/
@Before
public void test_before() {
linkedList = new LinkedList<>();
// 添加元素到链表开头
linkedList.addFirst(0);
// 添加元素到链表开头
linkedList.add(1);
// 将元素添加在指定索引位置处
linkedList.add(2, 2);
// 添加元素到链表末尾
linkedList.addLast(3);
System.out.println("-----------------------------------------");
System.out.println("LinkedList(直接输出的): " + linkedList);
}
@Test
public void test_LinkedList() {
System.out.println("-----------------------------------------");
// 返回此列表的第一个元素
System.out.println("getFirst()获得第一个元素: " + linkedList.getFirst());
// 返回此列表的最后一个元素
System.out.println("getLast()获得第最后一个元素: " + linkedList.getLast());
// 移除并返回此列表的第一个元素
System.out.println("removeFirst()删除第一个元素并返回该元素: " + linkedList.removeFirst());
// 移除并返回此列表的最后一个元素
System.out.println("removeLast()删除最后一个元素并返回该元素: " + linkedList.removeLast());
System.out.println("After remove:" + linkedList);
// 判断此列表包含指定元素,如果是,则返回true
System.out.println("contains()方法判断列表是否包含1这个元素:" + linkedList.contains(1));
// 返回此列表的元素个数
System.out.println("该linkedList的大小 : " + linkedList.size());
System.out.println("-----------------------------------------");
}
/**
* 位置访问操作
*/
@Test
public void test_set() {
System.out.println("-----------------------------------------");
// 将此列表中指定位置的元素替换为指定的元素
linkedList.set(1, 3);
System.out.println("After set(1, 3):" + linkedList);
// 返回此列表中指定位置处的元素
System.out.println("get(1)获得指定位置(这里为1)的元素: " + linkedList.get(1));
System.out.println("-----------------------------------------");
}
/**
* search位置访问操作
*/
@Test
public void test_search(){
System.out.println("-----------------------------------------");
linkedList.add(3);
System.out.println("After add(3):" + linkedList);
// 返回此列表中首次出现的指定元素的索引
System.out.println("indexOf(3): " + linkedList.indexOf(3));
// 返回此列表中最后出现的指定元素的索引
System.out.println("lastIndexOf(3): " + linkedList.lastIndexOf(3));
System.out.println("-----------------------------------------");
}
/**
* Queue操作
*/
@Test
public void test_queue(){
System.out.println("-----------------------------------------");
// 获取但不移除此列表的头
System.out.println("peek(): " + linkedList.peek());
// 获取但不移除此列表的头
System.out.println("element(): " + linkedList.element());
// 获取并移除此列表的头
Integer poll = linkedList.poll();
System.out.println("poll element: " + poll);
System.out.println("After poll():" + linkedList);
// 获取并移除此列表的头
linkedList.remove();
System.out.println("After remove():" + linkedList);
// 将指定元素添加到此列表的末尾
linkedList.offer(4);
System.out.println("After offer(4):" + linkedList);
System.out.println("-----------------------------------------");
}
/**
* Deque操作
*/
@Test
public void test_deque() {
System.out.println("-----------------------------------------");
// 在此列表的开头插入指定的元素
linkedList.offerFirst(2);
System.out.println("After offerFirst(2):" + linkedList);
// 在此列表末尾插入指定的元素
linkedList.offerLast(5);
System.out.println("After offerLast(5):" + linkedList);
// 获取但不移除此列表的第一个元素
System.out.println("peekFirst(): " + linkedList.peekFirst());
// 获取但不移除此列表的第一个元素
System.out.println("peekLast(): " + linkedList.peekLast());
// 获取并移除此列表的第一个元素
linkedList.pollFirst();
System.out.println("After pollFirst():" + linkedList);
// 获取并移除此列表的最后一个元素
linkedList.pollLast();
System.out.println("After pollLast():" + linkedList);
// 将元素推入此列表所表示的堆栈(插入到列表的头)
linkedList.push(2);
System.out.println("After push(2):" + linkedList);
// 从此列表所表示的堆栈处弹出一个元素(获取并移除列表第一个元素)
linkedList.pop();
System.out.println("After pop():" + linkedList);
linkedList.add(3);
// 从此列表中移除第一次出现的指定元素(从头部到尾部遍历列表)
linkedList.removeFirstOccurrence(3);
System.out.println("After removeFirstOccurrence(3):" + linkedList);
// 从此列表中移除最后一次出现的指定元素(从尾部到头部遍历列表)
linkedList.removeLastOccurrence(3);
System.out.println("After removeFirstOccurrence(3):" + linkedList);
System.out.println("-----------------------------------------");
}
@Test
public void test_for(){
System.out.println("-----------------------------------------");
linkedList.clear();
for (int i = 0; i < 100000; i++) {
linkedList.add(i);
}
// iterator迭代器遍历
long start = System.currentTimeMillis();
Iterator<Integer> iterator = linkedList.iterator();
while (iterator.hasNext()) {
iterator.next();
}
long end = System.currentTimeMillis();
System.out.println("Iterator:" + (end - start) + " ms");
// 顺序遍历(随机遍历)
start = System.currentTimeMillis();
for (int i = 0; i < linkedList.size(); i++) {
linkedList.get(i);
}
end = System.currentTimeMillis();
System.out.println("for:" + (end - start) + " ms");
// 另一种增强for循环遍历
start = System.currentTimeMillis();
for (Integer i : linkedList)
;
end = System.currentTimeMillis();
System.out.println("foreach:" + (end - start) + " ms");
// 通过pollFirst()或pollLast()来遍历LinkedList
LinkedList<Integer> temp1 = new LinkedList<>();
temp1.addAll(linkedList);
start = System.currentTimeMillis();
while (temp1.size() != 0) {
temp1.pollFirst();
}
end = System.currentTimeMillis();
System.out.println("pollFirst()或pollLast():" + (end - start) + " ms");
// 通过removeFirst()或removeLast()来遍历LinkedList
LinkedList<Integer> temp2 = new LinkedList<>();
temp2.addAll(linkedList);
start = System.currentTimeMillis();
while (temp2.size() != 0) {
temp2.removeFirst();
}
end = System.currentTimeMillis();
System.out.println("removeFirst()或removeLast():" + (end - start) + " ms");
System.out.println("-----------------------------------------");
}
}