LinkedList源码分析

获取指定位置的节点。(这个方法很重要,LinkedList中主要的几个方法都使用了这个方法)

private Entry<E> entry(int index) {
    if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
    Entry<E> e = header;
    // 获取index处的节点。
    // 若index<双向链表长度的1/2,则从前向后查找;否则,从后向前查找。这样能提高效率。
    if (index < (size >> 1)) {
        for (int i = 0; i <= index; i++)
            e = e.next;
    } else {
        for (int i = size; i > index; i--)
            e = e.previous;
    }
    return e;
}

一、返回LinkedList指定位置的元素

public E get(int index) {
    return entry(index).element;
}

二、设置index位置对应的节点的值为element

public E set(int index, E element) {
    Entry<E> e = entry(index);
    E oldVal = e.element;
    e.element = element;
    return oldVal;
}

三、将元素添加到LinkedList中

public boolean add(E e) {
    //将节点(e)添加到表头之前。也就是将节点添加到双向链表的末端。
    addBefore(e, header);
    return true;
}
在index前添加节点,且节点的值为element
public void add(int index, E element) {
    addBefore(element, (index==size ? header : entry(index)));
}

将节点(节点数据是e)添加到entry节点之前。

private Entry<E> addBefore(E e, Entry<E> entry) {
    Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
    newEntry.previous.next = newEntry;
    newEntry.next.previous = newEntry;
    size++;        // 修改LinkedList大小
    modCount++;   // 修改LinkedList的修改统计数:用来实现fail-fast机制。
    return newEntry;
}

四、LinkedList的删除操作

public E remove(int index) {
    return remove(entry(index));
}

// 遍历双向循环链表,如存在元素(o)则删除该元素并返回true;否则,返回false。

public boolean remove(Object o) {
    if (o==null) {  // 若o为null的删除情况
        for (Entry<E> e = header.next; e != header; e = e.next) {
            if (e.element==null) {
                remove(e);
                return true;
            }
        }
    } else {   // 若o不为null的删除情况
        for (Entry<E> e = header.next; e != header; e = e.next) {
            if (o.equals(e.element)) {
                remove(e);
                return true;
            }
        }
    }
    return false;
}

//将节点从链表中删除

private E remove(Entry<E> e) {
    if (e == header)
        throw new NoSuchElementException();
    E result = e.element;
    e.previous.next = e.next;    //改变指针的指向。
    e.next.previous = e.previous;
    e.next = e.previous = null;  //这一步和下一步是将当前节点的前后指针置为null,并将其元素值置为null。
    e.element = null;
    size--;
    modCount++;
    return result;
}

五、清空双向链表

public void clear() {
    Entry<E> e = header.next;
    // 从表头开始,逐个向后遍历;对遍历到的节点执行一下操作:
    // (1)设置当前节点的前后指针都为null,并且设置它的内容为null
    // (2)设置后一个节点为新的当前节点
    while (e != header) {
        Entry<E> next = e.next;
        e.next = e.previous = null;
        e.element = null;
        e = next;
    }
    header.next = header.previous = header;
    size = 0;   //设置大小为0
    modCount++;
}

六、将集合添加到LinkedList中

// 实际上,是从双向链表的末尾开始,将集合添加到双向链表中。
public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);
}
// 从双向链表的index开始,将集合添加到双向链表中。
public boolean addAll(int index, Collection<? extends E> c) {
    if (index < 0 || index > size)
        throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
    Object[] a = c.toArray();  //先将集合转换为数组
    int numNew = a.length;  // 获取集合的长度
    if (numNew==0)
        return false;
    modCount++;
    // 设置当前要插入节点的后一个节点
    Entry<E> successor = (index==size ? header : entry(index));
    // 设置当前要插入节点的前一个节点
    Entry<E> predecessor = successor.previous;
    // 将被插入的集合插在这两个节点之间
    for (int i=0; i<numNew; i++) {
        Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);
        predecessor.next = e;
        predecessor = e;
    }
    successor.previous = predecessor;
    size += numNew;  //最后,调整LinkedList的实际大小
    return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值