常见的List接口的实现类---LinkedList

LinkedList的使用与实现(源码分析)

类定义

public class LinkedList<E>
    extends AbstractSequentialList<E>  Sequential 相继的,按次序的   
    implements List<E>,  实现List接口 

    Deque<E>,  实现双向队列接口

    Cloneable,  实现克隆接口

    java.io.Serializable  实现序列化接口

public abstract class AbstractSequentialList<E> extends AbstractList<E>

AbstractSequentialList继承自AbstractList,是LinkedList的父类,是List接口的简化版实现。简化在哪儿呢?简化在AbstractSequentialList只支持按次序访问 ,而不像AbstractList那样支持随机访问。

属性

transient int size = 0; 存储的元素个数
transient Node<E> first; 头结点
transient Node<E> last; 尾结点

    //节点的定义
    private static class Node<E> {  静态内部类
        E item;  节点上存储的具体数据
        Node<E> next;  指向下一个节点
        Node<E> prev;  指向上一个节点

		//创建节点对象的参数
		// prev前一个节点的引用  element具体存储的数据   next下一个节点引用
        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

构造器

创建一个空列表

public LinkedList() {
}

没有指定容积的构造器,理论上来说,链表实际上没有长度限制,但是int size属性要求元素个数必须在[0,]

add方法的定义

    //在双向链表的末尾新增元素
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
    
    void linkLast(E e) {
        final Node<E> l = last;  缓存尾节点
        final Node<E> newNode = new Node<>(l, e, null); 创建新的节点
        last = newNode;  将尾指针执行新创建的节点
        if (l == null)  如果原来的尾节点为null,则新增的节点应该是链表的第一个节点
            first = newNode; 将头指针指向新创建的节点
        else
            l.next = newNode; 如果原来的尾节点不为null,则表示已经有元素了,将原来的尾节点指向新创建的节点,这样就将新节点加入到链表中
        size++; 链表中的元素个数+1
        modCount++; 修改次数+1
    }

add(int,Object) 在指定位置新增元素,原来位置上的元素后移

    public void add(int index, E element) {
        checkPositionIndex(index);  //检查index的合法性,要求index应该是在[0,size]的范围内

        if (index == size)
            linkLast(element); //如果索引值index等于size,则在链表默认添加元素
        else  在指定下标位置之前添加元素
            linkBefore(element, node(index));
    }

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

    //获取指定位置上的节点对象
    Node<E> node(int index) {
        if (index < (size >> 1)) { 如果序号值小于size/2则从头指针开始遍历链表,查找指定索引值的元素Node
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next; 从前向后遍历
            return x;
        } else {  如果序号值大于等于size/2则从尾指针开始遍历链表,查找指定索引值的元素Node
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;  从后向前遍历
            return x;
        }
    }
    
    //在指定节点对象之前添加e数据
    void linkBefore(E e, Node<E> succ) {
        final Node<E> pred = succ.prev;  获取指定位置的前一个节点
        final Node<E> newNode = new Node<>(pred, e, succ);  创建节点对象,参数1是原始节点的的前一个节点,参数2是具体存储的数据,参数3是原始位置上的节点
        succ.prev = newNode;  设置原始位置上的node对象的前一个节点为新建的节点【双向链表】
        if (pred == null)  如果指定位置的节点的前一个节点为null,则插入的新节点应该是头结点
            first = newNode;  使头指针指向新创建的节点
        else  设置前一个节点的下一个节点指针指向新创建的节点
            pred.next = newNode;
        size++;  元素个数+1
        modCount++; 修改次数+1
    }

删除元素remove

    //删除和参数相等的第一个元素,删除成功返回true,否则返回false
    public boolean remove(Object o) {
        if (o == null) { 删除值为null的元素,使用==判断   调用其他方法会出空指针异常
            for (Node<E> x = first; x != null; x = x.next) {  从头指针开始执行遍历,查找第一个值为null的节点
                if (x.item == null) {  判断当前节点的值是否为null
                    unlink(x);  删除指定的Node节点,并且返回Node中存储的数据
                    return true;
                }
            }
        } else {  删除值为非null的元素,判断使用equals方法
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {  判断当前需要删除的数据和节点中的数据是否相等
                    unlink(x);  删除指定的Node节点,并且返回Node中存储的数据
                    return true;
                }
            }
        }
        return false;
    }
    
    //删除指定的Node节点,并且返回Node中存储的数据
    E unlink(Node<E> x) {  
        final E element = x.item;  获取节点中的数据
        final Node<E> next = x.next;  获取节点的下一个节点对象的引用
        final Node<E> prev = x.prev;  获取上一个节点

        if (prev == null) {  如果当前节点的前一个节点为null,则表示当前节点为头节点
            first = next;  使头指针指向当前节点的下一个节点
        } else {  如果不是头节点
            prev.next = next;  上一个节点的下一个节点为当前节点的下一个节点,将当前节点从链表中剔除出来
            x.prev = null;  当前节点的上一个节点赋null值
        }

        if (next == null) {  如果当前节点的下一个节点为null,则表示当前节点为尾节点
            last = prev;  使尾指针指向当前节点的上一个节点
        } else {  如果不是尾节点
            next.prev = prev;  下一个节点的上一个节点引用值为当前节点的上一个节点,将当前节点从链表中剔除出来
            x.next = null;  当前节点的下一个节点赋null值
        }

        x.item = null;  将当前节点的数据赋null值
        size--;  链表中的元素个数-1
        modCount++;  修改次数+1
        return element;  返回当前节点原来的数据
    }
    //按照指定的索引序号删除对应的元素,同时返回删除元素的具体数据值
    public E remove(int index) {
        checkElementIndex(index);  检查序号值是否合法,不合法抛出IndexOutOfBoundsException  index >= 0 && index < size;
        return unlink(node(index));  首先查找指定索引序号对应的节点对象,然后删除对应的节点,返回原来节点上存储的具体数据
    }

修改操作set

    public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x = node(index);
        E oldVal = x.item;  //获取原始节点存储的数据
        x.item = element;   //修改节点上的数据为新值
        return oldVal;   //返回原始存储的数据
    }

查找操作indexOf

    //如果找到则返回索引序号,如果没找到则返回-1
    public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值