【Java面试】LinkedList和ArrayList的异同点

我们先把LinkedList的增删改查源码都阅读一遍,然后再各个方面进行比较两者之间的区别。

LinkedList linkedList = new LinkedList();
// add
linkedList.add("1");
// get
linkedList.get(0);
// set
linkedList.set(0, "1");
// remove
linkedList.remove("1");

ArrayList是对象数组,LinkedList是链表

先从新增开始,他的步骤也十分的简单,和ArrayList完全不同的是,一看他的数据结构,属性中包含next多半是链表的结构,但是具体是什么链表,我们还要继续看他的其他方法。

/**
 * Links e as last element.
 */
void linkLast(E e) {
    // 最后一个元素赋值给l
    final LinkedList.Node<E> l = last;
    // 新建一个节点赋值给newNode
    // 下一个节点为空
    // item为设置的节点
    // 最后一个节点赋值给上一个节点
    final LinkedList.Node<E> newNode = new LinkedList.Node<>(l, e, null);
    // 当前新建的节点赋值为最后一个节
    last = newNode;
    // 最后一个节点为空
    // 也就是第一个节点被设置的时候
    if (l == null)
        // 设置最新的节点为第一个节点
        first = newNode;
    else
        // 新增前的最后一个节点的next属性为当前新增节点
        l.next = newNode;
    // 长度自增
    size++;
    modCount++;
}

LinkedList是双向链表

我们再看看他内部的Node对象有哪些属性。

Node(LinkedList.Node<E> prev, E element, LinkedList.Node<E> next) {
	// 当前节点
    this.item = element;
    // 下一个节点
    this.next = next;
    // 上一个节点
    this.prev = prev;
}

然后继续看他的取数逻辑是怎样的,一会儿从前面第一个节点开始,一会儿从最后一个节点开始取数。

/**
 * Returns the (non-null) Node at the specified element index.
 */
LinkedList.Node<E> node(int index) {
    // assert isElementIndex(index);

    // 下标 小于 长度除以2
    if (index < (size >> 1)) {
        // 第一个节点赋值给x
        LinkedList.Node<E> x = first;
        // 正向遍历到下标节点为止
        for (int i = 0; i < index; i++)
            // x的下一个元素赋值给x
            x = x.next;
        // 返回到下标为止的x对象
        return x;
    } else {// 下标 大于等于 长度除以2
        // 最后一个节点赋值给x
        LinkedList.Node<E> x = last;
        // 反向遍历对象
        for (int i = size - 1; i > index; i--)
            x = x.prev;
        return x;
    }
}

一开始我对这个逻辑很费解,但是后来思考了一下,他是一个链表的结构,并且存储了第一个节点和最后一个节点作为遍历的开始节点,也就是双链表的结构。这里的index < (size >> 1)是为了判断从哪里开始遍历这个链表才能让,也就是我们常用的二分法,从而降低复杂度从而加快查询的速度。

再看看改的逻辑是什么,基本和取数的逻辑相似,只是做了item属性的替换而已。

/**
* Replaces the element at the specified position in this list with the
* specified element.
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E set(int index, E element) {
   checkElementIndex(index);
   // 和get逻辑类似
   Node<E> x = node(index);
   E oldVal = x.item;
   // 匹配到就修改他内部的item属性
   x.item = element;
   return oldVal;
}

删除的逻辑我最后定位都了unlink方法。

/**
 * Unlinks non-null node x.
 */
E unlink(LinkedList.Node<E> x) {
    // assert x != null;
    // x的值赋值个体element
    final E element = x.item;
    // x的下一个节点赋值给next
    final LinkedList.Node<E> next = x.next;
    // x的上一个节点赋值给prev
    final LinkedList.Node<E> prev = x.prev;

    // 上一个节点为空
    // 也就是当前节点是第一个节点
    if (prev == null) {
        // 第一个节点为下一个节点
        first = next;
    } else {
        // 下一个节点赋值给上一个节点的下一个节点
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;
    return element;
}

这个也很好理解,我们画个图理解一下。LinkedList删除开头末尾
LinkedList中间删除
他和ArrayList相同点是,他们都不是真正意义上的删除,被“删除”的空间还是被继续占用,前者是前后节点通知内容的替换,而后者则是本身数组的替换。


参考资料

总结

  • LinkedList是链表结构,ArrayList是对象数组。
  • LinkedList是双链表结构。
  • LinkedList和ArrayLsit都不是实际意义上的删除。

文章中出现的任何错误欢迎指正,共同进步!

最后做个小小广告,有对WEB开发和网络安全感兴趣的,可以加群一起学习和交流!

交流群
QQ:425343603

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章