LinkedList
LinkedList作为List的另一个实现类,它的底层数据结构是基于双向链表的,对于它的源码分析就是看对链表的分析,这就牵扯到数据结构,回想起作为科班出身的我,大学时期没有学好数据结构这门课,现在悔不当初啊。希望看到本文的计算机系的学生在校期间一定要学好数据结构,计网,计组这几门十分硬核的课程,这是你与那些培训出生的程序员唯一的优势了。
一、总览
从上图可以LinkedList也是队列的一种实现。
二、成员变量
//元素个数
transient int size = 0;
/**
* Pointer to first node.指向第一个节点
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
//头结点
transient Node<E> first;
/**
* Pointer to last node.指向最后一个节点
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
//尾节点
transient Node<E> last;
LinkedList作为一个双向链表,拥有头结点first、尾节点last、元素个数size。让我们看下这个Node内部类。
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;
}
}
这里的item就是指向我们放进LinkedList内的元素地址,next指向当前节点的下一节点(后驱节点),如果当前节点就是last节点,那next就指向null;prev指向当前节点的上一节点(前驱节点),如果当前节点就是first节点,那prev就指向null,如果LinkedList内没有任何元素,则first和last节点都为null。多个Node通过next和prev形成一个双向链表。
三、成员方法
1、往LinkedList添加元素
public boolean add(E e) {
linkLast(e);
return true;
}
public void addLast(E e) {
linkLast(e);
}
//添加e作为最后一个元素的item
void linkLast(E e) {
//记录没添加e元素之前LinkedList的尾节点
final Node<E> l = last;
//构造一个item为e,前驱节点prev为l(即之前的尾节点),后驱节点为null的一个node节点
final Node<E> newNode = new Node<>(l, e, null);
//让newNode作为该LinkedList的尾节点
last = newNode;
//如果没添加e元素之前LinkedList的尾节点为null,则说明当前LinkedList没有任何元素,那么让newNode作为该LinkedList的头节点(即first和last都为newNode),否则就让没添加e元素之前的尾节点的后驱节点指向newNode
if (l == null)
//newNode作为该LinkedList的头节点
first = newNode;
else
//让没添加e元素之前的尾节点的后驱节点指向newNode
l.next = newNode;
//元素个数+1
size++;
//链表结构变化次数+1
modCount++;
}
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
通过上面源码的分析,可以看出,往LinkedList添加元素只需要改变几个引用指向就行,相比于ArrayList的数组复制拷贝,效率高出很多,所以LinkedList的添加删除时间复杂度为O(1)。
2、查询
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index);
//先判断索引处于链表的前半段还是后半段(二分查找法?)
if (index < (size >> 1)) {
/*如果是处于前半段,则从头结点从前往后开始遍历
*/
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
//如果是处于后半段,则从尾结点从后往前开始遍历
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
3、
四、易错点
五、自己实现一遍LinkedList(单向)
package shujujiegou;
import com.sun.xml.internal.bind.v2.TODO;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author bpyin
* @ClassName LinkedListDemo
* @Description 单向链表的java实现
* @Date 2020/6/23 19:30
*/
public class LinkedList<T> {
/**
* add锁 防止多线程并发修改链表产生问题
*/
private static final ReentrantLock lock = new ReentrantLock();
/**
* 头结点 head--> ..... -->tail
*/
private volatile Node<T> head = null;
/**
* 尾节点 head--> ..... -->tail
*/
private volatile Node<T> tail = null;
/**
* 链表元素个数
*/
private volatile int size;
/**
* 链表元素个数
*
* @return
*/
public int size() {
return size;
}
/**
* 删除index处的元素
* @param index
* @return
*/
public synchronized T remove(int index) {
if (index < 0 || index >= size) {
throw new IllegalArgumentException("index 参数非法");
}
//暂存删除元素的前一个元素
Node<T> oldNodePrev = head;
//暂存删除元素
Node<T> oldNode = null;
if (index == 0) {
head = oldNodePrev.next;
oldNodePrev.next = null;
oldNode = oldNodePrev;
size--;
return oldNode.getValue();
}
for (int i = 0; i < index - 1; i++) {
oldNodePrev = oldNodePrev.next;
oldNode = oldNodePrev.next;
}
oldNodePrev.next = oldNode.next;
oldNode.next = null;//help gc
if (index == size - 1) {
tail = oldNodePrev;
}
size--;
return oldNode.getValue();
}
/**
* 删除第一个element元素(可能重复)
*
* @param element
* @return
*/
public T remove(T element) {
int index = indexOf(element);
if (index == -1) {
return null;
}
return remove(index);
}
/**
* 返回element元素的第一个索引(可能重复) 没有则返回-1
*
* @param element
* @return
*/
public int indexOf(T element) {
int i = 0;
for (Node node = head; node != null; node = node.next) {
if (node.getValue().equals(element)) {
return i;
}
i++;
}
return -1;
}
/**
* 链表是否包含element元素
*
* @param element
* @return
*/
public boolean contains(T element) {
return indexOf(element) != -1;
}
/**
* 在index位置插入一个元素
*
* @param index
* @param element 0->1->2->3 size 4
* @return
*/
public synchronized boolean add(int index, T element) {
if (index < 0 || index > size) {
throw new IllegalArgumentException("index 参数非法");
}
if (size == 0) {
//链表元素个数加1
size++;
//第一次add 链表为空 head和tail都为null
Node<T> node = new Node<>(element, null);
if (head == null || tail == null) {
head = tail = node;
return true;
}
//暂存旧head和tail
Node<T> tempHead = head;
Node<T> tempTail = tail;
//node节点成为最新的tail节点 并将旧tail的next后继节点引用指向node 完成链表的链接
tail = tempTail.next = node;
return true;
}
Node<T> newNode = new Node<T>(element);
if (index == 0) {
newNode.next = head;
head = newNode;
size++;
return true;
}
int i = 0;
for (Node node = head; node != null; node = node.next) {
//找到旧元素的前一个元素 此时的node就是
if (index - 1 == i) {
//将新元素的next指向旧元素的next
newNode.next = node.next;
node.next = newNode;
}
i++;
if (index == size) {
tail = newNode;
}
}
size++;
return true;
}
/**
* 添加一个元素到链表尾部 线程安全
*
* @param element
* @return
*/
public boolean add(T element) {
return add(size, element);
/*lock.lock();
try {
//链表元素个数加1
size++;
//第一次add 链表为空 head和tail都为null
Node<T> node = new Node<>(element, null);
if (head == null || tail == null) {
head = tail = node;
return true;
}
//暂存旧head和tail
Node<T> tempHead = head;
Node<T> tempTail = tail;
//node节点成为最新的tail节点 并将旧tail的next后继节点引用指向node 完成链表的链接
tail = tempTail.next = node;
return true;
} finally {
lock.unlock();
}*/
}
/**
* 根据索引获取元素
*
* @param index
* @return
*/
public T get(int index) {
if (index < 0 || index >= size) {
throw new ArrayIndexOutOfBoundsException("超过链表长度!");
}
//双向链表
if (index > size / 2) {
} else {
}
int i = 0;
for (Node<T> node = head; node != null; node = node.next) {
if (i == index) {
return node.getValue();
}
i++;
}
return null;
}
/**
* 返回头结点元素
*
* @return
*/
public T getFirst() {
/*
头结点为空,则证明链表上无任何元素,直接返回null
*/
return head == null ? null : head.getValue();
}
/**
* 返回尾结点元素
*
* @return
*/
public T getLast() {
/*
尾节点结点为空,则证明链表上无任何元素,直接返回null
*/
return tail == null ? null : tail.getValue();
}
@Override
public String toString() {
//废物代码
/*if (head==null){
return "[]";
}*/
String result = "[";
for (Node<T> node = head; node != null; node = node.next) {
result += node.getValue();
if (node.next != null) {
result += "-->";
}
}
result += "]" + "head=" + getFirst() + ";tail=" + getLast();
return result;
}
/**
* 链表节点 内部类
*
* @param <T>
*/
class Node<T> {
/**
* 存放真正的元素
*/
private T value;
/**
* 指向后继节点,形成单向链表
*/
private Node<T> next;
/**
* 指向前驱节点,结合next形成双向链表
*/
Node<T> prev;
public Node(T value, Node next) {
this.value = value;
this.next = next;
}
public Node(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
}