ArrayList 与 LinkedList 异同

异:
  1. 数据结构上:ArrayList底层数据结构是数组,而LinkedList采用的是双向链表。

  2. 查找,删除,插入元素上:因为ArrayList是数组,所以查找元素的时间复杂度为O(1),删除和插入元素,需要大量的移动元素,时间复杂度为O(n)。
    LinkedList虽然是双向链表,但他的删除元素remove(Element e)和删除指定位置元素remove(int index)的时间复杂度并不是O(1),只是近似O(1), 因为只有你直接传进来的是链表节点,时间复杂度才是O(1),而这里删除元素,传进来的都不是节点。需要LinkedList去自己通过node(int index)方法找到位置对应的节点的前一个节点才能改变节点的next指向进行删除。如果直接删除元素,没有传进来元素的index,就LinkedList就需要从头开始遍历找到元素。插入操作也是,如果是中间插入,也需要遍历链表,得到index对应的元素

JDK1.7及以后的版本做了优化,里面有fist和last两个引用分别指向双向链表的首节点和尾结点,通过比较int index离哪一端比较近,就从哪一端开始遍历,找到对应位置的节点

查找元素的时间复杂度就更是O(n)了。所以并不推荐使用LinkedList。

  1. ArrayList支持随机访问,它实现了RandomAccess接口,但RandomAccess接口只是一个声明式接口,告诉Collection的binarySearch()方法,ArrayList支持随机访问,调用
    indexedBinarySearch()方法。因为indexedBinarySearch()方法中就是通过midVal = list.get(mid)来得到中间值。

而 LinkedList没有索引,不支持随机快速访问,通过iteratorBinarySearch()方法,迭代器遍历。

4. 实现了RandomAccess接口的ArrayList ,优先选择普通for循环 ,其次foreach。因为其内部数组的索引i是可以快速访问到元素。
未实现RandomAccess接口的LinkedList, 优先选择iterator遍历。如果在for循环中,相当于是两层嵌套,每一个i, 都要从头或者从尾开始遍历,时间复杂度为O(n2)。而foreach遍历底层是通过iterator实现的,其内部curr的next可以依次指向下一个节点。

同:

都是线程不安全的。

参考:https://www.cnblogs.com/NickyYe/p/4461454.html
https://blog.csdn.net/m0_37884977/article/details/80467658
芋道源码

Linkedlist近似O(1)问题:LinkedList 的 源码

node(int index)

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中删除指定元素, 没有index, 从头开始遍历

public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

移除指定位置上的元素,用到node(index)。

public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

在指定的位置上添加新的元素,如果不是在链表尾部添加的话,也有通过node(index)来遍历index对应的节点。不过这种情况比较少,一般都是在依次添加。

    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

增加一个新的元素:(新添加的元素位于LinkedList的头结点),时间复杂度:O(1),因为LinkedList有一个fist索引指向头结点.

public void push(E e) {
        addFirst(e);
    }

indexedBinarySearch()和iteratorBinarySearch()源码:

Collections是集合的一个工具类,我们看一下Collections源码中的二分搜索方法。

public static <T>
    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
            return Collections.indexedBinarySearch(list, key);
        else
            return Collections.iteratorBinarySearch(list, key);
    }

判断list是否是RandomAccess的实例,如果是,则执行indexedBinarySearch方法,如果不是,则执行iteratorBinarySearch方法

private static <T>
int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
    int low = 0;
    int high = list.size()-1;
    while (low <= high) {
        int mid = (low + high) >>> 1;
        Comparable<? super T> midVal = list.get(mid);
        int cmp = midVal.compareTo(key);
        if (cmp < 0)
            low = mid + 1;
        else if (cmp > 0)
            high = mid - 1;
        else
            return mid; // key found
    }
    return -(low + 1);  // key not found
}
private static <T>
int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
{
    int low = 0;
    int high = list.size()-1;
    ListIterator<? extends Comparable<? super T>> i = list.listIterator();
    while (low <= high) {
        int mid = (low + high) >>> 1;
        Comparable<? super T> midVal = get(i, mid);
        int cmp = midVal.compareTo(key);
        if (cmp < 0)
            low = mid + 1;
        else if (cmp > 0)
            high = mid - 1;
        else
            return mid; // key found
    }
    return -(low + 1);  // key not found
}

实现了RandomAccess接口的List使用索引遍历,而未实现RandomAccess接口的List使用迭代器遍历。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值