LinkedList和ArrayList异同

LinkedList
定义:List接口的链表实现,并提供了一些队列,栈,双端队列操作的方法;
特点:1、分配内存空间不是必须是连续的;
          2、插入、删除操作很快,只要修改前后指针就OK了;
          3、访问比较慢,必须得从第一个元素开始遍历;

ArrayList
定义:是一个动态数组。
特点:1、随机访问速度快,插入和移除性能较差(数组的特点);
          2、支持null元素;
          3、有顺序;
          4、元素可以重复;
          5、线程不安全;

ArrayList和LinkedList的相同点:
ArrayList和Linkedlist都实现List接口。

ArrayList和LinkedList的不同点:
以增加和删除元素为例比较ArrayList和LinkedList的不同之处:

(1)增加元素到列表尾端:
在ArrayList中增加元素到队列尾端的代码如下:
public boolean add(E e){
   ensureCapacity(size+1);//确保内部数组有足够的空间
   elementData[size++]=e;//将元素加入到数组的末尾,完成添加
   return true;      
} 

ArrayList中add()方法的性能决定于ensureCapacity()方法。ensureCapacity()的实现如下:
public vod ensureCapacity(int minCapacity){
  modCount++;
  int oldCapacity=elementData.length;
  if(minCapacity>oldCapacity){    //如果数组容量不足,进行扩容
      Object[] oldData=elementData;
      int newCapacity=(oldCapacity*3)/2+1;  //扩容到原始容量的1.5倍
      if(newCapacitty<minCapacity)   //如果新容量小于最小需要的容量,则使用最小
                                                    //需要的容量大小
         newCapacity=minCapacity ;  //进行扩容的数组复制
         elementData=Arrays.copyof(elementData,newCapacity);
  }
}

LinkedList 的add()操作实现如下,它也将任意元素增加到队列的尾端:
public boolean add(E e){
   addBefore(e,header);//将元素增加到header的前面
   return true;
}

其中addBefore()的方法实现如下:
private Entry<E> addBefore(E e,Entry<E> entry){
     Entry<E> newEntry = new Entry<E>(e,entry,entry.previous);
     newEntry.provious.next=newEntry;
     newEntry.next.previous=newEntry;
     size++;
     modCount++;
     return newEntry;
}

(2)增加元素到列表任意位置:
由于ArrayList是基于数组实现的,而数组是一块连续的内存空间,如果在数组的任意位置插入元素,必然导致在该位置后的所有元素需要重新排列,因此,其效率相对会比较低。
以下代码是ArrayList中的实现:
public void add(int index,E element){
   if(index>size||index<0)
      throw new IndexOutOfBoundsException(
        "Index:"+index+",size: "+size);
         ensureCapacity(size+1);
         System.arraycopy(elementData,index,elementData,index+1,size-index);
         elementData[index] = element;
         size++;
}

对LinkedList来说,在List的尾端插入数据与在任意位置插入数据是一样的,不会因为插入的位置靠前而导致插入的方法性能降低。
以下代码是 LinkedList中的实现:
public void add(int index,E element){
   addBefore(element,(index==size?header:entry(index)));
}

(3)删除任意位置元素:
对ArrayList来说,在任意位置移除元素后,都要进行数组的重组。ArrayList的实现如下:
public E remove(int index){
   RangeCheck(index);
   modCount++;
   E oldValue=(E) elementData[index];
  int numMoved=size-index-1;
  if(numMoved>0)
     System.arraycopy(elementData,index+1,elementData,index,numMoved);
     elementData[--size]=null;
     return oldValue;
}

在LinkedList的实现中,首先要通过循环找到要删除的元素。如果要删除的位置处于List的前半段,则从前往后找;
 若其位置处于后半段,则从后往前找。因此无论要删除较为靠前或者靠后的元素都是非常高效的。
LinkedList 的实现如下:
public E remove(int index){
  return remove(entry(index));         
}
private Entry<E> entry(int index){
  if(index<0 || index>=size)
      throw new IndexOutBoundsException("Index:"+index+",size:"+size);
      Entry<E> e= header;
      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;
}

(4)容量参数:它表示初始化的数组大小。
ArrayList提供了一个可以制定初始数组大小的构造函数:
public ArrayList(int initialCapacity) 

(5)遍历列表:
构造一个拥有100万数据的ArrayList和等价的LinkedList,用forEach操作,迭代器和for循环遍历。
测试结果的相对耗时如下表所示:

可以看到,最简便的ForEach循环并没有很好的性能表现,综合性能不如普通的迭代器,而是用for循环通过随机访问遍历列表时,ArrayList表项很好,但是LinkedList的表现却无法让人接受,甚至没有办法等待程序的结束。这是因为对LinkedList进行随机访问时,总会进行一次列表的遍历操作。性能非常差,应避免使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值