zoukankan      html  css  js  c++  java
  • Linkedlist源码

    LinkedList也和ArrayList一样实现了List接口,但是它执行插入和删除操作时比ArrayList更加高效,因为它是基于链表的。基于链表也决定了它在随机访问方面要比ArrayList逊色一点。

       

    除此之外,LinkedList还提供了一些可以使其作为栈、队列、双端队列的方法。这些方法中有些彼此之间只是名称的区别,以使得这些名字在特定的上下文中显得更加的合适。

       

    先看LinkedList类的定义。

       

       

    LinkedList继承自AbstractSequenceList、实现了ListDeque接口。其实AbstractSequenceList已经实现了List接口,这里标注出List只是更加清晰而已。

       

    AbstractSequenceList提供了List接口骨干性的实现以减少实现List接口的复杂度。

       

    Deque接口定义了双端队列的操作。

       

    LinkedList中之定义了两个属性:

       

    private transient Entry<E> header = new Entry<E>(null, null, null);

    private transient int size = 0;

       

    header是链表的头结点了,Entry就是节点对象了。一下是Entry类的代码。

       

    private static class Entry<E> {

    E element;

    Entry<E> next;

    Entry<E> previous;

       

    Entry(E element, Entry<E> next, Entry<E> previous) {

    this.element = element;

    this.next = next;

    this.previous = previous;

    }

    }

       

    只定义了存储的元素、前一个元素、后一个元素,这就是双向链表的节点的定义,每个节点只知道自己的前一个节点和后一个节点。

       

    来看LinkedList的构造方法。

       

    public LinkedList() {

    header.next = header.previous = header;

    }

    public LinkedList(Collection<? extends E> c) {

    this();

    addAll(c);

    }

       

    LinkedList提供了两个构造方法。

       

    第一个构造方法不接受参数,只是将header节点的前一节点和后一节点都设置为自身(注意,这个是一个双向循环链表,如果不是循环链表,空链表的情况应该是header节点的前一节点和后一节点均为null),这样整个链表其实就只有header一个节点,用于表示一个空的链表。

       

    第二个构造方法接收一个Collection参数c,调用第一个构造方法构造一个空的链表,之后通过addAllc中的元素全部添加到链表中。来看addAll的内容。

       

    public boolean addAll(Collection<? extends E> c) {

    return addAll(size, c);

    }

    // index参数指定collection中插入的第一个元素的位置

    public boolean addAll(int index, Collection<? extends E> c) {

    // 插入位置超过了链表的长度或小于0,报IndexOutOfBoundsException异常

    if (index < 0 || index > size)

    throw new IndexOutOfBoundsException("Index: "+index+

    ", Size: "+size);

    Object[] a = c.toArray();

    int numNew = a.length;

    // 若需要插入的节点个数为0则返回false,表示没有插入元素

    if (numNew==0)

    return false;

    modCount++;

    // 保存index处的节点。插入位置如果是size,则在头结点前面插入,否则获取index处的节点

    Entry<E> successor = (index==size ? header : entry(index));

       

    // 获取前一个节点,插入时需要修改这个节点的next引用

    Entry<E> predecessor = successor.previous;

    // 按顺序将a数组中的第一个元素插入到index处,将之后的元素插在这个元素后面

    for (int i=0; i<numNew; i++) {

    // 结合Entry的构造方法,这条语句是插入操作,相当于C语言中链表中插入节点并修改指针

    Entry<E> e = new Entry<E>((E)a[i], successor, predecessor);

       

    // 插入节点后将前一节点的next指向当前节点,相当于修改前一节点的next指针

    predecessor.next = e;

       

    // 相当于C语言中成功插入元素后将指针向后移动一个位置以实现循环的功能

    predecessor = e;

    }

    // 插入元素前index处的元素链接到插入的Collection的最后一个节点

    successor.previous = predecessor;

    // 修改size

    size += numNew;

    return true;

    }

       

       

    http://www.cnblogs.com/hzmark/archive/2012/12/25/LinkedList.html

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 数的统计
    Java实现 蓝桥杯VIP 算法训练 和为T
    Java实现 蓝桥杯VIP 算法训练 友好数
    Java实现 蓝桥杯VIP 算法训练 连续正整数的和
    Java实现 蓝桥杯VIP 算法训练 寂寞的数
    Java实现 蓝桥杯VIP 算法训练 学做菜
    Java实现 蓝桥杯VIP 算法训练 暗恋
    Java实现 蓝桥杯VIP 算法训练 暗恋
    测试鼠标是否在窗口内,以及测试鼠标是否在窗口停留
    RichEdit 各个版本介绍
  • 原文地址:https://www.cnblogs.com/keedor/p/4409681.html
Copyright © 2011-2022 走看看