目录
一级目录
二级目录
三级目录
1.LinkedList概述
-
LinkedList是一个顺序容器
-
是线程安全的
-
允许存放null值
-
允许存放重复值
-
底层采用双向循环链表进行存储
LinkedList同时实现了List接口和Deque接口
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList既可以看作是一个顺序容器,也可以看作是一个队列,同时又能看作是一个栈
栈和队列都可以使用LinkedList,java官方已经声明不支持使用Stack类了,而且也没有一个Queue类(这是接口)可供使用
但是目前ArrayDeque是栈和队列的首选,性能上比linkedList好。
public void linkedListTest(){
LinkedList<String> list = new LinkedList<>();
list.offer("加入到队列的尾部");
list.push("加入到栈的顶部");
list.offerFirst("加入到队列的头部");
list.add("加入到集合的尾部");
list.add("再来一个");
System.out.println("操作前数据:");
for (String s : list) {
System.out.println(s);
}
System.out.println("--------------访问并不删除栈顶的元素-------------");
System.out.println(list.peekFirst());
System.out.println(list.peek());
System.out.println(list.peekLast());//访问并不删除栈尾元素
System.out.println("-------------将栈顶元素弹栈---------------");
System.out.println(list.pop());
System.out.println("-------------访问并删除队列第一个元素---------------");
System.out.println(list.poll());
System.out.println(list.pollFirst());
System.out.println(list.pollLast());
System.out.println("-------------最后剩下的---------------");
for (String s : list) {
System.out.println(s);
}
}
2. 分析源码
2.1 底层数据结构
LinkedList包含了一个私有静态内部类Node来维护双向链表
源码如下:
transient int size = 0;
transient Node<E> first;//指向第一个节点的指针
transient Node<E> last;//指向最后一个节点的指针
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;
}
}
2.2 Linkedlist集合方法
getFirst(),getLast()
public Object getFirst()
获取第一个元素
public Object getLast()
获取最后一个元素
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
removeFirst(),removelast()
public Object removeFirst()
删除第一个,并返回那个元素
public Object removeLast()
删除最后一个元素,并返回那个元素
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
//一些方法底层实际使用的都是removeFirst方法
public E remove() {
return removeFirst();
}
public E pop() {
return removeFirst();
}
remove(e),remove(index)
remove(Object o)
删除指定元素
remove(int index)
删除指定下标处元素
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
public E remove(int index) {
checkElementIndex(index);//检查元素下标是否合法
return unlink(node(index));
}
//取消非空链接节点
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
//一些方法底层实际使用的是remove(Object o)
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
add(e)
add(E e)在linkedList末尾插入元素
add(int index,E e)在指定下标处插入元素,需要先通过线性查找,找到具体位置,在进行插入操作
public boolean add(E e) {
linkLast(e);
return true;
}
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
addAll()
addAll(int index)并不是直接通过循环调用add(index,e),有两个原因
-
效率低下
-
fail-fast中的modCount只会增加一次
从指定位置开始,将指定集合中的所有元素插入此列表。将当前位于该位置的元素(如果有的话)和所有后续元素向右移动(增加它们的索引)。新元素将按照指定集合的迭代器返回它们的顺序出现在列表中。包含要添加到此列表的元素的集合c,如果该列表因调用而改变,则返回:true。如果索引超出范围(index < 0 || index > size())则抛出:IndexOutOfBoundsException
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
clear()
为了让GC更快的回收放置的元素,需要将node之间的引用关系赋为null
public void clear() {
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
get()
get(int index)
获取指定下标元素
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
set()
set(int index,E e)
将指定下标位置的元素重新赋值
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
判断索引的方法
outOfBoundsMsg(int index)
构造一个IndexOutOfBoundsExecption
的详细消息
checkElementIndex(int index)
检查当前下标是否存在元素
checkPositionIndex(int index)
检查当前下标是否是迭代器或添加操作的有效位置下标
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
indexOf()和lastIndexOf()
indexOf(Object o)
查找第一次出现元素的下标,如果找不到,返回-1
lastIndexOf(Object o)
查找最后一次出现元素的下标,如果找不到,返回-1
Queue方法
peek()查找但不删除次列表的第一个元素,如果列表为空,则返回null
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
element()查找但不删除次列表的第一个元素
public E element() {
return getFirst();
}
poll()查找并删除此集合的第一个元素,返回此集合的第一个元素,如果此集合为空,则返回null
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
remove()查找并删除此集合的第一个元素
public E remove() {
return removeFirst();
}
offer(E e)将指定元素添加到集合的尾部,添加成功返回true,否则为false
public boolean offer(E e) {
return add(e);
}
Deque方法
offerFirst(E e)将指定元素插入到集合的前面
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
offerLast(E e)将指定元素插入到集合的后面
public boolean offerLast(E e) {
addLast(e);
return true;
}
peekFirst()查询但不删除此集合的第一个元素,如果此集合为空,则返回null
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
peekLast()查询但不删除此集合的最后一个元素,如果此集合为空,则返回null
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
pollFirst()查询并删除此集合的第一个元素,如果此集合为空则返回null
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
pollLast()查询并删除此集合的最后一个元素,如果此集合为空则返回null
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
push(E e)将一个元素进行压栈操作,即将元素插入到列表的前面
public void push(E e) {
addFirst(e);
}
pop()从此集合中进行弾栈操作,即删除并返回该列表的第一个元素
public E pop() {
return removeFirst();
}
removeFirstOccurrence(Object o)删除此集合中第一次出现的指定元素,如果集合不包含该元素,则不做改变,如果包含该元素,则从集合中移除
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
removeLastOccurrence(Object o)删除此集合中最后一次出现的指定元素,如果集合不包含该元素,则该元素不变,如果包含该元素,则从集合中移除
public boolean removeLastOccurrence(Object o) {
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}