学过数据结构的都知道,理论上,链表相比数组在删除方面更加有优势,原因在于数组在删除后,需要将删除位置后面的元素都向前移动一位。但是如果是指定删除第几个元素(如删除位置处于整个数组的中间)的情况下就不一样了。测试代码如下
public class test { public static void main(String[] args) { ArrayList list = new ArrayList(); for(int i = 0 ; i < 100000;i++){ list.add(i); } int n =list.size(); long time1 = System.currentTimeMillis(); while (!((n--)==0)){ list.remove(n/2); } long time2 = System.currentTimeMillis(); System.out.println(time2-time1+"ms"); } }
最后测试结果如下:
Linklist代码:
public class test { public static void main(String[] args) { LinkedList list = new LinkedList(); for(int i = 0 ; i < 100000;i++){ list.add(i); } int n =list.size(); long time1 = System.currentTimeMillis(); while (!((n--)==0)){ list.remove(n/2); } long time2 = System.currentTimeMillis(); System.out.println(time2-time1+"ms"); } }
测试结果:
分析原因:
ArrayList中remove方法中,有源码如下:
private void fastRemove(Object[] es, int i) { modCount++; final int newSize; if ((newSize = size - 1) > i) System.arraycopy(es, i + 1, es, i, newSize - i); es[size = newSize] = null; }
可见调用了System.arraycopy方法()进行了删除元素后的,元素向前移位操作。
而LinkedList 查找被删除的节点代码如下:
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; } }
分析原因为System.arraycopy这个方法是个native方法,性能优良,以下文章有进行测试,
Java性能漫谈-数组复制之System.arraycopy - yakovchang - 博客园 (cnblogs.com)https://www.cnblogs.com/yakovchang/p/java_system_arraycopy.html 推断由于是array是个连续数组,可放入cpu的缓存中,因此访问速度会快很多,而相比之下LinkedList存储比较零散,需要多次访存,且本身的结构也比较复杂,因此不用位移元素的优势被完全抵消了。
结论,如果大部分操作都是在数组中间进行删除和增加,而不是头插,使用ArrayList会获得更好的性能。