【Java集合框架库】LinkedList类

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--;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值