LinkedList类
LinkedList和ArrayList有一些相似,我们知道ArrayList是以数组实现,它的优势是查询性能高,劣势是按顺序增删性能差。如果在不确定元素数量的情况时,不建议使用ArrayList。这种情况下,我们就可以使用LinkedList了。
LinkedList是以双向链表
实现的。既然它是以链表来实现的,所以也会有链表的基本特性。又因为其是使用双向链表来实现的,所以重点还是在于双向链表的特性。
- 链表无容量限制,但双向链表本身使用了更多空间,也需要额外的链表指针操作。
- 除了实现List接口外,LinkedList还为在列表的开头及结尾get、remove和insert元素提供了统一的命名方法。这些操作可以将链接列表当作栈,队列和双端队列来使用。
LinkedList类的继承结构
从上面我们可以看到,LinkedList继承的类与实现的接口如下:
- Collection 接口、List 接口、Cloneable 接口、Serializable 接口、Deque 接口(5个接口)
- AbstractCollection 类、AbstractList 类、AbstractSequentialList 类(3个类)
- 其中Deque定义了一个线性Collection,支持在两端插入和删除元素。
LinkedList的特点
LinkedList 使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,其实对内存的利用率更高),按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
- LinkedList是通过双向链表去实现的。
- 从LinkedList的实现方式中可以看出,因为它底层实现是链表,所以它不存在容量不足的问题。
- LinkedList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写出“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
- LinkdedList的克隆函数,即是将全部元素克隆到一个新的LinkedList中。
- 由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。
- LinkedList可以作为FIFO(先进先出)的队列。
- LinkedList可以作为LIFO(后进先出)的栈。
- 遍历LinkedList时,使用removeFirst()或removeLast()效率最高。但是用它们遍历会删除原始数据;若只是单纯的取数据,而不删除,建议用迭代器方式或者foreach方式。无论如何,千万不要用随机访问去遍历LinkedList!因为这样的效率非常非常低。
LinkedList和ArrayList的对比
相同点:
- 1、接口实现:都实现了List接口,都是线性列表的实现。
- 2、线程安全:都是线程不安全的,都是基于fail-fast机制。
不同点:
- 1、底层:ArrayList内部是数组实现,而LinkedList内部实现是双向链表结构。
- 2、接口:ArrayList实现了RandomAccess可以支持随机元素访问,而LinkedList实现了Deque可以当做队列使用。
- 3、性能:新增、删除元素时ArrayList需要使用到拷贝原数组,而LinkedList只需移动指针,查找元素 ArrayList支持随机元素访问,而LinkedList只能一个结点一个结点的去遍历。
LinkedList的结构设计
1、继承结构
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
2、成员变量
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;
3、构造方法
/**
* Constructs an empty list.
*/
public LinkedList() {
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
4、底层结构设计
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;
}
}
LinkedList操作的部分实现
在这里,仅仅是自己重新实现LinkedList相关操作的方法。
辅助操作
- 判断传入的下标是否合法
/**
* 判断传入的下标是否合法
*/
public void rangeCheck(int index){
if(index < 0 || index > size){
throw new IndexOutOfBoundsException();
}
}
- 获取下标结点
/**
* 获取下标结点
*/
public Node<T> NodeIndex(int index){
if(index < (size >> 1)){
Node<T> node = first;
for(int i = 0;i < index;i++){
node = node.next;
}
return node;
}else {
Node<T> node = last;
for(int i = size - 1;i > index;i--){
node = node.prev;
}
return node;
}
}
插入元素
- 尾部插入
/**
* 插入元素
* 尾部插入
*/
public void add(T item){
Node<T> l = last;
Node<T> newNode = new Node<>(l,item,null);
last = newNode;
if(l == null){
first = newNode;
}else {
l.next = newNode;
}
size++;
}
- 在指定位置插入元素
/**
* 插入元素
* 在指定位置插入元素
*/
public void add(int index, T item){
rangeCheck(index);
if(index == size){
add(item);
return;
}
Node<T> pos = NodeIndex(index);
Node<T> pre = pos.prev;
Node<T> newNode = new Node<>(pre,item,pos);
pos.prev = newNode;
if(pre == null){
first = newNode;
}else {
pre.next = newNode;
}
size++;
}
删除元素
- 删除指定位置的元素
/**
* 删除元素
* 删除指定位置的元素
*/
public void remove(int index){
rangeCheck(index);
if(index == size){
throw new IndexOutOfBoundsException();
}
Node<T> pos = NodeIndex(index);
Node<T> pre = pos.prev;
Node<T> next = pos.next;
pos.item = null; //将元素置空
if(pre == null){
first = next;
}else {
pre.next = next;
pos.prev = null; //若有前驱则将前驱置空
}
if(next == null){
last = pre;
}else {
next.prev = pre;
pos.next = null; //若有后继则将后继置空
}
size--;
}
- 删除指定元素
/**
* 删除元素
* 删除指定元素
*/
public void remove(T item){
if(item == null){
int count = 0;
for(Node<T> node = first;node != null;node = node.next){
if(node.item == null){
remove(count);
}
count++;
}
}else {
int count = 0;
for(Node<T> node = first;node != null;node = node.next){
if(node.equals(item)){
remove(count);
}
count++;
}
}
}
更改元素
/**
* 更改元素
*/
public void set(int index, T item){
rangeCheck(index);
if(index == size){
throw new IndexOutOfBoundsException();
}
Node<T> pos = NodeIndex(index);
pos.item = item;
}
获取元素
/**
* 获取元素
*/
public T get(int index){
rangeCheck(index);
if(index == size){
throw new IndexOutOfBoundsException();
}
Node<T> pos = NodeIndex(index);
return pos.item;
}
迭代器模式
- 获取迭代器对象
/**
* 获取迭代器对象
*/
public Itr iterator(){
return new Itr();
}
/**
* 迭代器模式
*/
private class Itr implements Iterator<T>{
private int curIndex;
private int posIndex;
private Node<T> pos = null;
private Node<T> next;
public Itr(){
next = (curIndex == size) ? null : first;
}
@Override
public boolean hasNext() {
return curIndex < size;
}
@Override
public T next() {
if(!hasNext()){
throw new IndexOutOfBoundsException();
}
if(next != null){
pos = next;
next = next.next;
}
posIndex = curIndex;
curIndex++;
return pos.item;
}
@Override
public void remove() {
if(posIndex == size){
throw new IndexOutOfBoundsException();
}
MyLinkedList.this.remove(posIndex);
curIndex--;
}
}