ArrayList和LinkedList的reverse实现

java集合类中的ArrayList和LinkedList都实现了List接口,都实现了get,add,set,size,remove等列表操作。但是ArrayList的底层实现是数组,LinkedList的底层实现是双向链表。这意味着ArrayList的get(int index),set(int index,E element)操作的时间复杂度为O(1),与索引的大小无关,而LinkedList的get,set需要线性检索链表,时间复杂度和index的大小成正比。基于数组和链表在检索性能上的不同,实现reverse的策略也不相同。
下面是ArrayList的reverse实现


public ArrayList reverse(ArrayList list){
        int size=list.size();
        ArrayList reversedList=new ArrayList(size);
        for(int i=size-1;i>-1;i--){
            reversedList.add(list.get(i));
        }
        return reversedList;
    }

ArrayList源码中的add方法如下,如果不需要给数组扩容,那么add的时间复杂度总是O(1)。所以在reverse的实现中,用原始的list的size初始化一个reversedList,这样每次for循环的执行时间都是常数级的时间成本。最终的时间复杂度是O(size)。

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

LinkedList的reverse实现如下

public LinkedList reverse(LinkedList list){

        if(list.getFirst()==null){
            return null;
        }
        LinkedList reversedList=new LinkedList();
        E item=null;
        int n=list.size();
        for(int i=0;i

LinkedList的add和ArrayList的add都是常数级的时间复杂度,但是LinkedList通过index索引的时间复杂度是index线性函数,所以这里for循环里不能通过索引来得到原始LinkedList的元素引用。考虑到LinkedList的底层实现是双向链表,可以实现类似栈的pop操作,对应的api为removeLast(),源码如下

public E removeLast() {
        final Node l = last;
        if (l == null)
            throw new NoSuchElementException();
        return unlinkLast(l);
    }
private E unlinkLast(Node l) {
        // assert l == last && l != null;
        final E element = l.item;
        final Node prev = l.prev;
        l.item = null;
        l.prev = null; // help GC
        last = prev;
        if (prev == null)
            first = null;
        else
            prev.next = null;
        size--;
        modCount++;
        return element;
    }
    }

从源码中看到,弹出列表末节点只涉及修改倒数第二个节点的链接,这个操作也是常数级的复杂度。

你可能感兴趣的:(ArrayList和LinkedList的reverse实现)