原理:
LinkedList不同于ArrayList,是一种的是双向链表的数据结构
继承关系
LinkedList:重要的属性和构造方法
public class LinkedList<E> extends AbstractSequentialList<E> implements
List<E>, Deque<E>, Queue<E>, Cloneable, Serializable {
//集合元素数量
transient int size = 0;
//空节点,很多操作都离不开它,在无参构造中进行初始化
transient Link<E> voidLink;
//内部类包装了元素
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;
}
//无参构造,初始化了voidLink变量,并将其previous、next进行赋值
public LinkedList() {
voidLink = new Link<E>(null, null, null);
voidLink.previous = voidLink;
voidLink.next = voidLink;
}
}
无参构造创建了一个Link的对象voidLink!
- 增加(无需指定位置)
@Override
public boolean add(E object) {
//直接调用addLastImpl方法
return addLastImpl(object);
}
private boolean addLastImpl(E object) {
//1.第一次添加,从无参构造上,可以发现voidLink的previous、next都是voidLink本身。
//2.集合中不止volidLink一个节点,从刚才1的注释顺序来看,voidLink.previous是之前的newLink,也就是上次新添加到队尾的节点
Link<E> oldLast = voidLink.previous;
//1.从内部类的构造来看,newLink的previous指向了oldLast,而oldLast是voidLink.previous,voidLink.previous又是voidLink本身。newLink的next指向了voidLink。
//2..从内部类的构造来看,newLink的previous指向了oldLast,而oldLast是voidLink.previous,voidLink.previous是之前的newLink(这次叫oldLast )。newLink的next指向了voidLink。
Link<E> newLink = new Link<E>(object, oldLast, voidLink);
//将voidLink.previous赋值为newLink
voidLink.previous = newLink;
//1.上文说过了oldLast就是voidLink本身,将voidLink.next赋值为newLink;
//2.上文说过了oldLast就是上次新添加到队尾的节点,将oldLast.next赋值为newLink;
oldLast.next = newLink;
//元素数量+1
size++;
//计数器+1
modCount++;
return true;
}
画图来说明一下这个添加过程吧!
接下来我们再一次执行添加元素,相信大家根据源码就可以明白下面图片的内容了
总结来说,不指定index的add,直接加入到链表的结尾,将newLink的previous指向链尾的oldLast,next指向voidLind,然后voidLink的previous指向newLink,链尾的oldLast的next指向newLink,然后增加元素数量,计数器数量,完成整个添加操作
- 增加(指定位置)
@Override
public void add(int location, E object) {
if (location >= 0 && location <= size) {
//初始化link,赋值为voidLink(空节点很重要的变量,现在看出来了吧,很多操作都离不开它)
Link<E> link = voidLink;
//采用二分法,如果是location在前半段,就从voidLink一路next下去向后查找,如果是后半段就一路prevvious像前查找。
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> newLink = new Link<E>(object, previous, link);
previous.next = newLink;
link.previous = newLink;
size++;
modCount++;
} else {
throw new IndexOutOfBoundsException();
}
}
相信大家看过之前的add 这里逻辑应该都不陌生了。接下来贴出删除等操作,大家掌握的思想,看起来就容易多了
- 删除
@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();
}
- 修改
@Override
public E set(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;
}
}
E result = link.data;
link.data = object;
return result;
}
throw new IndexOutOfBoundsException();
}
- 查找
@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();
}