
LinkedList(双向链表)不仅实现了 List 接口,还实现了 Deque(双端队列)接口。
实现了List<E>, Deque<E>, Cloneable, java.io.Serializable等接口
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
主要维护了这样三个值(都不可以被序列化),first链表头指针,last链表尾指针,还有size
当然里面的节点类是一个双向节点,如下:
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;
}
}//内部的节点类——双向链表
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
构造器不多只有两个,但是这个addAll方法需要注意(实现的是一种操作——把一条链表在某个地方剪开,把一段新的链条接进去,再把剩下的接好)
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)// 如果 pred 是 null,说明是在头部插入
first = newNode;
else
pred.next = newNode;// 否则,把前一个节点的 next 指向新节点
pred = newNode;//移动指针:把 pred 指向刚刚插入的这个新节点
}
//重新连接断开的部分
if (succ == null) {
last = pred;
} else {
pred.next = succ;// 新链条末尾的 next 指向原来的后继节点
succ.prev = pred;// 原来后继节点的 prev 指向新链条的末尾
}
size += numNew;
modCount++;
return true;
}
这一段看代码即可,逻辑非常清晰,其实和直接链表插入一个节点也没什么太大区别
public boolean add(E e) {
linkLast(e);
return true;
}
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++;
}//是直接在末尾添加的
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}//获取队首元素,但不从链表中删除它
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}//出掉队首的元素
public boolean offer(E e) {
return add(e);
}//直接加到队尾
public void push(E e) {
addFirst(e);
}//入栈
public E pop() {
return removeFirst();
}//出栈
这一部分就是一些常见的用法的源代码,其实就是链表操作,而且由于是双端链表甚至都不需要进行遍历就可以进行操作了
- 作为 List(列表):add(末尾添加元素)、get(获取元素)
- 作为 Queue(队列):offer(入队)、poll(出队)、peek(查看队首元素)
- 作为 Deque(双端队列 / 栈):push(压栈)、pop(出栈)
- 更通用的方法:removeFirst、removeLast、addFirst、addLast(所有的都是由这些构成的)
这些在我们用Java写代码题目的时候是很常见的,实在忘记了我们也可以使用最后一排的方法直接来操作,但是实际上,我们算法里面除了树图,其他的基本都是数组形式的多,但是在快速构建上,这些方法还是很方便的
List<String> list = new LinkedList<>();
list.add("A");
list.get(0);
Queue<String> queue = new LinkedList<>();
queue.offer("A"); // 入队
queue.poll(); // 出队
Deque<String> stack = new LinkedList<>();//作为栈的时候,对应Deque
stack.push("Top"); // 压栈
stack.pop(); // 弹栈
在现代 Java 开发中(尤其是 JDK 8 之后),ArrayList 通常是默认首选,LinkedList因为双端本来就浪费了很多资源,而且还是链表形式进行遍历非常麻烦,因此List里面主要还是使用ArrayList
而且LinkedList 同样不是线程安全的,LinkedList的实现在(JDK1.6 之前为循环链表,JDK1.7 取消了循环)
1227

被折叠的 条评论
为什么被折叠?



