【Java集合框架之LinkedList】

一、 LinkedList 介绍

1. 概况

LinkedList类是双向列表,列表中的每个节点都包含了对前一个和后一个元素的引用,它和ArrayList一样实现了List接口,但是她执行插入和删除操作时比ArrayList更加高效,因为她是基于链表的,但同时也决定了她在随机访问方面要比ArrayList弱一点。

2. 选择使用 ArrayList 还是 LinkedList

以下情况使用 ArrayList :

  • 频繁访问列表中的某一个元素。
  • 只需要在列表末尾进行添加和删除元素操作。

以下情况使用 LinkedList :

  • 你需要通过循环迭代来访问列表中的某些元素。
  • 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。

3. LinkedList 继承类和实现接口

  • 继承了 AbstractSequentialList 类,实现了一些顺序存取的 List 的通用方法以减少继承类的代码量。
  • 实现了 Queue 接口,可作为队列使用。
  • 实现了 List 接口,可进行列表的相关操作。
  • 实现了 Deque 接口,可作为队列使用。
  • 实现了 Cloneable 接口,可实现克隆。
  • 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。

4. 成员属性

// 版本号
private static final long serialVersionUID = 876323262645176354L;
// LinkedList 的 Size
transient int size = 0;
// 双向链表的头节点
transient Node<E> first;
// 双向链表的尾节点
transient Node<E> last;

其中 Node 为内部类,包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。 size是双向链表中节点实例的个数。

5.构造方法

// 引入 LinkedList 类
import java.util.LinkedList; 

LinkedList<E> list = new LinkedList<E>();   // 普通创建方法
或者
LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表

二、常用方法

方法描述
public boolean add(E e)链表末尾添加元素,返回是否成功,成功为 true,失败为 false
public void add(int index, E element)向指定位置插入元素
public boolean addAll(Collection c)将一个集合的所有元素添加到链表后面,返回是否成功,成功为 true,失败为 false
public boolean addAll(int index, Collection c)将一个集合的所有元素添加到链表的指定位置后面,返回是否成功,成功为 true,失败为 false
public void addFirst(E e)元素添加到头部
public void addLast(E e)元素添加到尾部
public boolean offer(E e)向链表末尾添加元素,返回是否成功,成功为 true,失败为 false
public boolean offerFirst(E e)头部插入元素,返回是否成功,成功为 true,失败为 false
public boolean offerLast(E e)尾部插入元素,返回是否成功,成功为 true,失败为 false
public void clear()清空链表
public E removeFirst()删除并返回第一个元素
public E removeLast()删除并返回最后一个元素
public boolean remove(Object o)删除某一元素,返回是否成功,成功为 true,失败为 false
public E remove(int index)删除指定位置的元素
public E poll()删除并返回第一个元素
public E remove()删除并返回第一个元素
public boolean contains(Object o)判断是否含有某一元素
public E get(int index)返回指定位置的元素
public E getFirst()返回第一个元素
public E getLast()返回最后一个元素
public int indexOf(Object o)查找指定元素从前往后第一次出现的索引
public int lastIndexOf(Object o)查找指定元素最后一次出现的索引
public E peek()返回第一个元素
public E element()返回第一个元素
public E peekFirst()返回头部元素
public E peekLast()返回尾部元素
public E set(int index, E element)设置指定位置的元素
public Object clone()克隆该列表
public Iterator descendingIterator()返回倒序迭代器
public int size()返回链表元素个数
public ListIterator listIterator(int index)返回从指定位置开始到末尾的迭代器
public Object[] toArray()返回一个由链表元素组成的数组
public T[] toArray(T[] a)返回一个由链表元素转换类型而成的数组

三、LinkedList 迭代器

1. ListIterator

ListIterator 继承了 Iterator ,以允许双向遍历列表和修改元素。

ListIterator 存在于 List 集合之中,通过调用方法可以返回起始下标为 index的迭代器,可以在任意一个下标位置返回该迭代器,且可以实现双向遍历。

public interface ListIterator<E> extends Iterator<E> {
    boolean hasNext();//判断集合中是否存在下一个对象
    E next();//返回集合中的下一个对象,并将访问指针移动一位
    boolean hasPrevious();//判断集合中是否存在上一个对象
    E previous();//返回集合中的上一个对象,并将访问指针移动一位
    int nextIndex();//返回下一个对象的下标位置
    int previousIndex();//返回上一个对象的下标位置
    void remove();//删除集合中调用next()方法返回的对象
    void set(E e);
    void add(E e);
}

从其提供的方法可以看到 LinkedList 不仅可以向后迭代,也可以向前迭代方法如下:

public class ArrayTest {
    public static void main(String[] args) {
        LinkedList<Person> list = new LinkedList<Person>();
        list.add(new Person(35, "张三", "男"));
        list.add(new Person(30, "李四", "男"));
        list.add(new Person(29, "王五", "男"));
        list.add(new Person(29, "刘六", "男"));
        // 获取一个类型为 ListIterator 的迭代器,并将初始游标位置设定在 index = size() 处
        ListIterator<Person> iterator = list.listIterator(list.size());
        // 向前迭代 LinkedList
        while(iterator.hasPrevious()){
            System.out.println(iterator.previous());
        }

    }
}

输出结果:

刘六29男
王五29男
李四30男
张三35男

迭代器内部提供了 remove() 和 add() 方法因此在迭代过程中可以对 LinkedList 进行结构性的改变,但不能调用 LinkedList 自己的方法,否则会导致 ConcurrentModificationException 异常。

2. descendingIterator

​ LinkedList 还提供了另一个内部类 DescendingIterator,其作用就是在向前迭代 LinkedList 的过程中让用户可以依然使用 next() 而不用使用 previous() 。

public static void main(String[] args) {
    LinkedList<Person> list = new LinkedList<Person>();
    list.add(new Person(35, "张三", "男"));
    list.add(new Person(30, "李四", "男"));
    list.add(new Person(29, "王五", "男"));
    list.add(new Person(29, "刘六", "男"));
    // 获取一个倒叙迭代器
    Iterator<Person> iterator = list.descendingIterator();
    // 向前迭代 LinkedList
    while(iterator.hasNext()){
        System.out.println(iterator.next());
    }

}

输出结果:

刘六29男
王五29男
李四30男
张三35男

四、ArrayList和LinkedList的区别

1. 相同点

  • 两者都实现了Java的 List 接口,可以包含重复元素,并保持元素的顺序。
  • 它们都是非线程安全的集合,即在多线程环境中共享时需要外部同步。

2. 不同点

不同点ArrayListLinkedList
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持:O(1)不支持:O(N)
头部插入需要搬移元素,效率低O(N)只需要修改引用的指向,时间复杂度为O(1)
容量空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问频繁在任意位置插入和删除
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值