Java集合框架-List接口

LinkedList简介

  • LinkedList类是继承于AbstractSequentialList的双向链表。
  • LinkedList类实现了List接口,定义对集合的基本(包括与位置有关的操作)。
  • LinkedList类实现了Deque(Double End Queue)接口,可将LinkedList用作双端队列使用。
  • LinkedList实现了Cloneable接口,即覆盖了函数clone(),可进行克隆操作。
  • LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
  • LinkedList是非同步的。若在多线程的环境下使用,需要在外部进行同步操作。
  • LinkedList类定义如下,
public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable

LinkedList内部Node类

Node类定义如下,

private static class Node<E> {
        E item; //存储值
        Node<E> next;//指向下一个结点
        Node<E> prev;//指向上一个结点
    //构造函数,链接该结点的next和prev指针
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

LinkedList类的域

说明
int sizesize表示链表的长度
Node firstfirst指向链表中的第一个结点
Node lastlast指向链表中的最后一个结点

LinkedList的构造函数

//构造一个空链表
public LinkedList() {
}
//将集合c中的元素都添加到新建的链表中
public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
}

LinkedList中的方法

该部分主要介绍LinkedList中新添加的方法、实现的List方法和实现的Deque中的方法三部分。

LinkedList类中新添加的方法

//把值e链接到头部结点
private void linkFirst(E e) {
        final Node<E> f = first;
        final Node<E> newNode = new Node<>(null, e, f);//第一个参数是新建结点的前驱结点,第三个参数是新建结点的后继结点
        first = newNode;//第一个结点已经变为newNode,需重新设置first的值
        if (f == null)//如果先前的f结点为空,则证明该链表中没有任何结点,则只需设置last
            last = newNode;
        else//f!=null,则需要设置f的prev指正指向新的first
            f.prev = newNode;
        size++;//node结点个数加1
        modCount++;//链表的结构改变,即多了一个结点,modCount加1
    }
//把值为e的结点链接到链表的最后
void linkLast(E e) {
        final Node<E> l = last;//记录未改变之前的最后一个结点
        final Node<E> newNode = new Node<>(l, e, null);//新建值为e的结点,并设置前驱结点和后继结点
        last = newNode;//最后一个结点已经改变,需设置新值
        if (l == null)//l的值为null,则证明先前的链表为空,则只需设置first指针
            first = newNode;
        else //l!=null,链表不为空,则需要设置l的next指针
            l.next = newNode;
        size++;
        modCount++;
    }
//在结点succ(succ!=null)之前插入值为e的结点
void linkBefore(E e, Node<E> succ) {
        // assert succ != null;
        final Node<E> pred = succ.prev;//记录succ的前驱结点
        final Node<E> newNode = new Node<>(pred, e, succ);//建立值为e的结点并设置新结点的前驱结点和后继结点
        succ.prev = newNode;//设置succ(succ!=null)的pre的值
        if (pred == null)//若pred为空,则证明succ为first,则设置first指向newNode
            first = newNode;
        else//若pred!=null,则需要设置pred的next指正
            pred.next = newNode;
        size++;
        modCount++;
    }
//删除第一个结点,
private E unlinkFirst(Node<E> f) {
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC,让GC回收内存
        first = next;//设置新的first
        if (next == null)//若链表只有一个结点
            last = null;
        else//新first结点的prev置为null
            next.prev = null;
        size--;
        modCount++;
        return element;
    }
//删除最后一个结点(和删除第一个结点类似)
private E unlinkLast(Node<E> l) {
        // assert l == last && l != null;
        final E element = l.item;
        final Node<E> prev = l.prev;//记录l的前驱结点
        l.item = null;
        l.prev = null; // help GC,让GC回收l和l.item所指向的对象所占的内存
        last = prev;//设置新的last
        if (prev == null)//若链表中只有一个结点
            first = null;
        else//prev!=null,则将prev.next置空,使最后一个结点变为非活动态。
            prev.next = null;
        size--;
        modCount++;
        return element;
    }
//删除任意一个结点x
E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;//记录x的后继结点
        final Node<E> prev = x.prev;//记录x的前驱结点

        if (prev == null) {//前驱结点为空,则证明x为first
            first = next;//则设置fisrt为next(x结点需要删除)
        } else {//prev!=null
            prev.next = next;//设置prev.next指向next
            x.prev = null;//x的prev指向null
        }

        if (next == null) {//若x的后继结点为空,则证明x为最后一个结点
            last = prev;//则设置last为prev
        } else {//next!=null
            next.prev = prev;//设置next.prev指向prev
            x.next = null;//x的next指向null
        }

        x.item = null;
        size--;
        modCount++;//链表结构改变,将modCount加1
        return element;//返回删除元素
    }
//返回链表中的第一个元素。若链表为空则抛出异常
public E getFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return f.item;
    }
//返回链表中最后一个元素,为空则抛出异常
public E getLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return l.item;
}
//删除并返回链表中的第一个元素
public E removeFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        return unlinkFirst(f);
}
//删除并返回链表中的最后一个元素
public E removeLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
}
//添加置为e的元素到链表首部
public void addFirst(E e) {
        linkFirst(e);
}
//添加置为e的元素到链表尾部
public void addLast(E e) {
        linkLast(e);
}
//返回链表中值为o的结点在链表中第一次出现时的下标。从前往后遍历
public int indexOf(Object o) {
        int index = 0;
        if (o == null) {//o为空
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {//o不为空
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;//如果不存在,则返回-1
}
//返回链表中值为o的结点在链表中最后一次出现时的下标。从后往前遍历
public int lastIndexOf(Object o) {
        int index = size;
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (x.item == null)
                    return index;
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (o.equals(x.item))
                    return index;
            }
        }
        return -1;
}
//返回指定位置的结点。若指定的位置比(size/2)小,则从前往后遍历。否则,从后往前扫描。
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;
        }
}

LinkedList类中实现List的方法

  • List接口中继承了Collection接口中的方法,并新定义了一些有关位置的方法。
  • 这些方法的实现绝大部分都依赖于 LinkedList类中新添加的方法 中介绍的方法,例如,

    
        public void add(int index, E element) {//在指定位置添加元素
            checkPositionIndex(index);//检查插入位置
            if (index == size)//表示在链表的最后插入元素
                linkLast(element);
            else//在node(index)之前插入元素
                linkBefore(element, node(index));
       }
    • 该部分主要用到两个方法来检查下标,
    //检查是否为链表中元素所在的下标,主要用于元素的存取操作
    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }
    //检查是否为元素的插入位置,主要用于元素的添加操作
    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

LinkedList类中实现的Deque中的方法

在这类方法主要设计栈和

方法说明
public E peek()返回链表中的第一个元素。链表为空,返回null
public E peekFirst()返回链表中的第一个元素。链表为空,返回null
public E peekLast()返回链表中的最后一个元素。链表为空,返回null
public E element()返回链表中的第一个元素。链表为空,返回异常
public E poll()删除并返回链表中的第一个元素。为空返回null
public E pollFirst()删除并返回链表中的第一个元素。为空返回null
public E pollLast()删除并返回链表中的最后一个元素。为空返回null
public E remove()删除并返回链表中的第一个元素。为空返回异常
public boolean offer(E e)在链表的最后添加值为e的结点
public boolean offerFirst(E e)在链表的首部添加值为e的结点
public boolean offerLast(E e)在链表的最后添加值为e的结点
public void push(E e)该方法主要用于模拟压栈的操作
public E pop()该方法主要用于模拟出栈的操作

LinkedList类中的Iterator

  • ListIterator接口继承自Iterator接口。
  • ListIterator可以向前、向后访问结点,而Iterator只能向后访问结点。
  • ListIterator的域,
private Node<E> lastReturned;//记录上一次访问过的结点
private Node<E> next;//记录下一个将要访问的结点
private int nextIndex;//记录结点元素的下标
private int expectedModCount = modCount;//链表的修改次数
  • ListIterator的构造函数,
//构造从指定位置开始的ListIterator。可以发现lastReturned变量并没有被设置值
ListItr(int index) {
            // assert isPositionIndex(index);
            next = (index == size) ? null : node(index);
            nextIndex = index;
}
  • ListIterator中的方法如下,
public boolean hasNext() {//是否还有元素
       return nextIndex < size;
}
//先将next结点保存在lastReturned中,然后next向后移动一个结点,并将lastReturned返回
public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();
            lastReturned = next;//保存当前结点
            next = next.next;//next往后移动一个结点
            nextIndex++;//nextIndex加1
            return lastReturned.item;//返回先前的next结点中的值
}
//前面是否还有结点
public boolean hasPrevious() {
            return nextIndex > 0;
}
//先进行next的前向移动,后进行lastReturned赋值,再将lastReturned返回
public E previous() {
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();

            lastReturned = next = (next == null) ? last : next.prev;
            nextIndex--;
            return lastReturned.item;
}
//删除lastReturned结点
public void remove() {
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();

            Node<E> lastNext = lastReturned.next;
            unlink(lastReturned);
            if (next == lastReturned)//当执行previous()函数时,会满足这一条件
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;
            expectedModCount++;
}
//设置刚刚访问的lastReturned的值
public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            checkForComodification();
            lastReturned.item = e;
}
//在next结点之前添加一个结点
public void add(E e) {
            checkForComodification();
            lastReturned = null;
            if (next == null)//next为null,则在最后添加该结点
                linkLast(e);
            else//在next之前添加结点
                linkBefore(e, next);
            nextIndex++;
            expectedModCount++;
}

疑问

  • void linkLast(E e) 方法为什么不是私有的?
  • public E getFirst() 方法中为什么f变量要设为final。

本文作者能力,知识有限,若有错误,欢迎留言指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值