LinkedList简介
LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
LinkedList 实现 list接口,具有集合的添加删除功能。
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。
LinkedList相对于ArrayList来说,是可以快速添加,删除元素,但是访问数据相对于ArrayList会比较慢
LinkedList属性
public class LinkedList<E> extends AbstractSequentialList<E> implements
List<E>, Deque<E>, Queue<E>, Cloneable, Serializable {
private static final long serialVersionUID = 876323262645176354L;
//链表大小
transient int size = 0;
//头节点
transient Link<E> voidLink;
LinkedList内部类
//节点类
private static final class Link<ET> {
//数据
ET data;
//该节点的前后节点引用
Link<ET> previous, next;
Link(ET o, Link<ET> p, Link<ET> n) {
data = o;
previous = p;
next = n;
}
}
LinkedList构造方法
public LinkedList() {
voidLink = new Link<E>(null, null, null);
voidLink.previous = voidLink;
voidLink.next = voidLink;
}
该构造方法创建一个空的队列
public LinkedList(Collection<? extends E> collection) {
this();
addAll(collection);
}
该构造方法先创建一个空的链表,并将构造方法里传进来的集合数据全部添加到链表当中
LinkedList方法
@Override
public boolean addAll(Collection<? extends E> collection) {
//获取集合大小
int adding = collection.size();
if (adding == 0) {
return false;
}
Collection<? extends E> elements = (collection == this) ?
new ArrayList<E>(collection) : collection;
//获取当前的节点的前驱节点
Link<E> previous = voidLink.previous;
//遍历集合数据
for (E e : elements) {
//根据数据创建新的数据节点
Link<E> newLink = new Link<E>(e, previous, null);
//设置前驱节点的下一节点为当前的新节点
previous.next = newLink;
//设置前驱节指向当前的新节点
previous = newLink;
}
//遍历完成之后当前的前驱几点为链表最后一个节点的前驱节点
previous.next = voidLink;
voidLink.previous = previous;
size += adding;
modCount++;
return true;
}
该方法将传入的集合中的数据添加到当前链表中
@Override
public void add(int location, E object) {
//判断节点插入的位置是链表长度范围之内
if (location >= 0 && location <= size) {
Link<E> link = voidLink;
//节点插入位置如果小于链表大小的一半则从链表的开始位置遍历下一节点
if (location < (size / 2)) {
for (int i = 0; i <= location; i++) {
link = link.next;
}
//节点插入位置如果大于或等于链表大小的一半则从链表的末尾位置遍历前一节点
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
//找到location位置的节点,并与前一节点断开连接,将新节点插入两个节点之间
Link<E> previous = link.previous;
Link<E> newLink = new Link<E>(object, previous, link);
previous.next = newLink;
link.previous = newLink;
size++;
modCount++;
} else {
throw new IndexOutOfBoundsException();
}
}
public void add(int location, E object) 方法 在location 位置添加一个节点,数据object@Override
public boolean add(E object) {
return addLastImpl(object);
}
private boolean addLastImpl(E object) {
Link<E> oldLast = voidLink.previous;
Link<E> newLink = new Link<E>(object, oldLast, voidLink);
voidLink.previous = newLink;
oldLast.next = newLink;
size++;
modCount++;
return true;
}
add(E object) 方法和 addLastImpl(E object) 在链表尾部插入新的数据节点
@Override
public boolean addAll(int location, Collection<? extends E> collection) {
if (location < 0 || location > size) {
throw new IndexOutOfBoundsException();
}
int adding = collection.size();
if (adding == 0) {
return false;
}
Collection<? extends E> elements = (collection == this) ?
new ArrayList<E>(collection) : collection;
Link<E> previous = voidLink;
if (location < (size / 2)) {
for (int i = 0; i < location; i++) {
previous = previous.next;
}
} else {
for (int i = size; i >= location; i--) {
previous = previous.previous;
}
}
Link<E> next = previous.next;
for (E e : elements) {
Link<E> newLink = new Link<E>(e, previous, null);
previous.next = newLink;
previous = newLink;
}
previous.next = next;
next.previous = previous;
size += adding;
modCount++;
return true;
}
该方法用来在链表某一位置插入一个集合 与 public boolean addAll(Collection<? extends E> collection) 方法相比增加了一个查找链表节点位置的流程,具体原理是判断当前节点的位置是在前半部分还是在后半部分,从而只需要遍历一半,提高运行效率。
public void addFirst(E object) {
addFirstImpl(object);
}
private boolean addFirstImpl(E object) {
Link<E> oldFirst = voidLink.next;
Link<E> newLink = new Link<E>(object, voidLink, oldFirst);
voidLink.next = newLink;
oldFirst.previous = newLink;
size++;
modCount++;
return true;
}
以上两个方法用于在链表头添加节点
@Override
public void clear() {
if (size > 0) {
size = 0;
voidLink.next = voidLink;
voidLink.previous = voidLink;
modCount++;
}
}
该方法用于清空链表,只需要改变链表当前节点的指向,全部指向自己
@Override
public boolean contains(Object object) {
Link<E> link = voidLink.next;
if (object != null) {
while (link != voidLink) {
if (object.equals(link.data)) {
return true;
}
link = link.next;
}
} else {
while (link != voidLink) {
if (link.data == null) {
return true;
}
link = link.next;
}
}
return false;
}
该方法用于判断链表中是否包含某一数据,方法时是遍历整个链表,直到找到该节点返回true或者遍历到头节点返回false
@Override
public E get(int location) {
if (location >= 0 && location < size) {
Link<E> link = voidLink;
if (location < (size / 2)) {
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
return link.data;
}
throw new IndexOutOfBoundsException();
}
该方法用于从头节点或尾节点开始遍历获取某一位置的节点的数据
public E removeFirst() {
return removeFirstImpl();
}
private E removeFirstImpl() {
Link<E> first = voidLink.next;
if (first != voidLink) {
Link<E> next = first.next;
voidLink.next = next;
next.previous = voidLink;
size--;
modCount++;
return first.data;
}
throw new NoSuchElementException();
}
该方法用于从头节点删除一个节点
@Override
public E remove(int location) {
if (location >= 0 && location < size) {
Link<E> link = voidLink;
if (location < (size / 2)) {
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
Link<E> previous = link.previous;
Link<E> next = link.next;
previous.next = next;
next.previous = previous;
size--;
modCount++;
return link.data;
}
throw new IndexOutOfBoundsException();
}
该方法用于删除某一位置的节点,通过遍历找到该节点并将该节点的前驱节点指向该节点的后继节点,返回该节点的值