线性表:顺序存储结构和链式存储结构
链式存储结构的优缺点:
- 优点:删除插入效率高
-
缺点:查询效率高
循环列表:将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相连的单链表称为单循环链表,简称循环链表
双向循环列表:双向循环链表是单向循环链表的每个结点中,再设置一个指向其前驱结点的指针域
对于空的双向循环列表
双向循环列表插入
双向列表的删除
LinkedList源码解析:双向列表而非循环列表
参数和构造函数源码解析
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;
}
}
迭代器源码解析
参数和构造函数源码解析
private static final class LinkIterator<ET> implements ListIterator<ET> {
final LinkedList<ET> list;
Link<ET> link, lastLink;//当前节点和最后一个节点
//双向列表
LinkIterator(LinkedList<ET> object, int location) {
list = object;
expectedModCount = list.modCount;//修改次数赋值
if (location >= 0 && location <= list.size) {
//设置当前节点为头指针
link = list.voidLink;
//二分查找
if (location < list.size / 2) {
for (pos = -1; pos + 1 < location; pos++) {
//当前节点为下一个节点
//循序查找
link = link.next;
}
} else {
for (pos = list.size; pos >= location; pos--) {
//倒序查找
link = link.previous;
}
}
} else {
throw new IndexOutOfBoundsException();
}
}
}
add添加源码解析,所以add并不是添加到尾部
public void add(ET object) {
if (expectedModCount == list.modCount) {
//指向下一个节点
//link代表01 link.next代表原来指向的02,现在插入03
Link<ET> next = link.next;//原本指向的下一个节点
//添加对象新建一个节点 link为前一个节点,next为下一个节点
Link<ET> newLink = new Link<ET>(object, link, next);
link.next = newLink;//当前01的指向为03
next.previous = newLink;//02的前一个指向03
link = newLink;//下一个节点则为03
lastLink = null;//最后一个为空
pos++;
expectedModCount++;
list.size++;
list.modCount++;
} else {
throw new ConcurrentModificationException();
}
}
添加头部源码解析
public void addFirst(E object) {
addFirstImpl(object);
}
private boolean addFirstImpl(E object) {
Link<E> oldFirst = voidLink.next;//原本指向01
Link<E> newLink = new Link<E>(object, voidLink, oldFirst);//object新建一个指针对象
voidLink.next = newLink;
oldFirst.previous = newLink;
size++;
modCount++;
return true;
}
添加尾部源码解析
public void addLast(E object) {
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;
}
是否有上下指针
public boolean hasNext() {
return link.next != list.voidLink;//不等于头指针就代表有下个指针
}
public boolean hasPrevious() {
return link != list.voidLink;
}
next源码解析
public ET next() {
if (expectedModCount == list.modCount) {
LinkedList.Link<ET> next = link.next;
if (next != list.voidLink) {//代表有下一个
lastLink = link = next;//默认这是最后一个指针和正处于的指针都为下一个指向的指针
pos++;
return link.data;//返回数据
}
throw new NoSuchElementException();
}
throw new ConcurrentModificationException();
}
移除源码解析
public void remove() {
if (expectedModCount == list.modCount) {
if (lastLink != null) {
Link<ET> next = lastLink.next; //next 最后节点下一个指针03
Link<ET> previous = lastLink.previous;//previous 最后节点上一个指针01
next.previous = previous;// next.previous为03的前一个指针指向01
previous.next = next;// previous.next 01的下一个指针指向03
if (lastLink == link) {
pos--;
}
link = previous;
lastLink = null;
expectedModCount++;
list.size--;
list.modCount++;
} else {
throw new IllegalStateException();
}
} else {
throw new ConcurrentModificationException();
}
}
补充一下,简单看下LinkedHashMap双向循环列表的add源码
@Override void addNewEntry(K key, V value, int hash, int index) {
LinkedEntry<K, V> header = this.header;//首先获取头部
LinkedEntry<K, V> eldest = header.nxt;
if (eldest != header && removeEldestEntry(eldest)) {
remove(eldest.key);
}
LinkedEntry<K, V> oldTail = header.prv;//头部指向前一个指针即最后一个元素
LinkedEntry<K, V> newTail = new LinkedEntry<K,V>(
key, value, hash, table[index], header, oldTail);//new一个新的指针
//头部前一个指向新的指针,原本最后一个元素的下一个指针指向新的指针
table[index] = oldTail.nxt = header.prv = newTail;
}