代码如下,比较丑见谅: int capacity = 100000, delCount = 10000; List<Integer> a1List = new ArrayList<Integer>(), a2List = new ArrayList<Integer>(), a3List = new ArrayList<Integer>(), l1List = new LinkedList<Integer>(), l2List = new LinkedList<Integer>(), l3List = new LinkedList<Integer>();
for( int i = 0; i < capacity; i++ ) { a1List.add( i ); a2List.add( i ); a3List.add( i ); l1List.add( i ); l2List.add( i ); l3List.add( i ); }
long start = 0, duration = 0;
start = System.currentTimeMillis(); for( int i = 0; i < delCount; i++ ) { a1List.remove( capacity - i - 1 ); } duration = System.currentTimeMillis() - start; System.out.println( "ArrayList尾部删除耗时:" + duration + "ms");
start = System.currentTimeMillis(); for( int i = 0; i < delCount; i++ ) { l1List.remove( capacity - i - 1 ); } duration = System.currentTimeMillis() - start; System.out.println( "LinkedList尾部删除耗时:" + duration + "ms");
start = System.currentTimeMillis(); for( int i = 0; i < delCount; i++ ) { a2List.remove( ( capacity - i - 1 ) / 2 ); } duration = System.currentTimeMillis() - start; System.out.println( "ArrayList中部删除耗时:" + duration + "ms" );
start = System.currentTimeMillis(); for( int i = 0; i < delCount; i++ ) { l2List.remove( ( capacity - i -1 ) / 2 ); } duration = System.currentTimeMillis() - start; System.out.println( "LinkedList中部删除耗时:" + duration + "ms" );
start = System.currentTimeMillis(); for( int i = 0; i < delCount; i++ ) { a3List.remove( 0 ); } duration = System.currentTimeMillis() - start; System.out.println( "ArrayList首部删除耗时:" + duration + "ms" );
start = System.currentTimeMillis(); for( int i = 0; i < delCount; i++ ) { l3List.remove( 0 ); } duration = System.currentTimeMillis() - start; System.out.println( "LinkedList首部删除耗时:" + duration + "ms" );
中部最耗时的原因你可以看jdk源码,位置小于一般长度从头读起大于一半长度从尾读起,自然最费时是读到中间
ArrayList尾部删除耗时:57ms
LinkedList尾部删除耗时:156ms
那尾部删除为什么依然是ArrayList效率高呢
那尾部删除为什么依然是ArrayList效率高呢尾部和中部有什么区别 ArrayList用下标没差
ArrayList尾部删除耗时:57ms
LinkedList尾部删除耗时:156ms如果是删最后一个元素,ArrayList删除只是将最后的元素置空,然后将size减少,LinkedList是进入元素所在节点,然后找到前一个节点,将前一个节点的next指向置空,ArrayList动作似乎更少可以试一下删除倒数第x个的元素,触发ArrayList数组的复制操作试验下
ArrayList底层就是一个Object[]数组,数组都是定长的,那么ArrayList怎么实现动态变长呢,那就是在需要时(比如添加新元素,原始的数组长度不够了),创建一个新的数组,然后把原始数据和新插入的数据copy到新的数组里面,如果是删除的话,删除项后面有元素时,后面的元素都有向前移动。
LinkedList底层实现不再是Object数组,而是一个单向的带头的双向链表(LinkedList的内部类Entry)。删除元素时,只需要修改要删除项的前一个元素的next引用和后一个元素的prev引用即可。
所以在删除方面,LinkedList要比ArrayList效率高一些。
数据结构好久没看过了,大致是这个意思吧,说的不对的地方,其他同志请指正。
那尾部删除为什么依然是ArrayList效率高呢尾部和中部有什么区别 ArrayList用下标没差
按2楼那位仁兄的说法,LinkedList当索引超过长度一般时是从尾部开始查找的,于是LinkedList的尾部删除和中部删除当然就不一样了。
List<Integer> a1List = new ArrayList<Integer>(),
a2List = new ArrayList<Integer>(),
a3List = new ArrayList<Integer>(),
l1List = new LinkedList<Integer>(),
l2List = new LinkedList<Integer>(),
l3List = new LinkedList<Integer>();
for( int i = 0; i < capacity; i++ ) {
a1List.add( i );
a2List.add( i );
a3List.add( i );
l1List.add( i );
l2List.add( i );
l3List.add( i );
}
long start = 0, duration = 0;
start = System.currentTimeMillis();
for( int i = 0; i < delCount; i++ ) {
a1List.remove( capacity - i - 1 );
}
duration = System.currentTimeMillis() - start;
System.out.println( "ArrayList尾部删除耗时:" + duration + "ms");
start = System.currentTimeMillis();
for( int i = 0; i < delCount; i++ ) {
l1List.remove( capacity - i - 1 );
}
duration = System.currentTimeMillis() - start;
System.out.println( "LinkedList尾部删除耗时:" + duration + "ms");
start = System.currentTimeMillis();
for( int i = 0; i < delCount; i++ ) {
a2List.remove( ( capacity - i - 1 ) / 2 );
}
duration = System.currentTimeMillis() - start;
System.out.println( "ArrayList中部删除耗时:" + duration + "ms" );
start = System.currentTimeMillis();
for( int i = 0; i < delCount; i++ ) {
l2List.remove( ( capacity - i -1 ) / 2 );
}
duration = System.currentTimeMillis() - start;
System.out.println( "LinkedList中部删除耗时:" + duration + "ms" );
start = System.currentTimeMillis();
for( int i = 0; i < delCount; i++ ) {
a3List.remove( 0 );
}
duration = System.currentTimeMillis() - start;
System.out.println( "ArrayList首部删除耗时:" + duration + "ms" );
start = System.currentTimeMillis();
for( int i = 0; i < delCount; i++ ) {
l3List.remove( 0 );
}
duration = System.currentTimeMillis() - start;
System.out.println( "LinkedList首部删除耗时:" + duration + "ms" );
ArrayList尾部删除耗时:57ms
LinkedList尾部删除耗时:156ms如果是删最后一个元素,ArrayList删除只是将最后的元素置空,然后将size减少,LinkedList是进入元素所在节点,然后找到前一个节点,将前一个节点的next指向置空,ArrayList动作似乎更少可以试一下删除倒数第x个的元素,触发ArrayList数组的复制操作试验下
我是楼主上面三连了回复不了试了一下,我发现LinkedList遍历耗时要比ArrayList数组复制耗时要多得多据我估计,LinkedList删除效率比ArrayList高的索引阀值应该是小于总数的一半的某个值,只有索引比这个阀值小的时候,LinkedList的删除操作效率才有优势前提是都是随机访问
请指正!
ArrayList尾部删除耗时:57ms
LinkedList尾部删除耗时:156ms如果是删最后一个元素,ArrayList删除只是将最后的元素置空,然后将size减少,LinkedList是进入元素所在节点,然后找到前一个节点,将前一个节点的next指向置空,ArrayList动作似乎更少可以试一下删除倒数第x个的元素,触发ArrayList数组的复制操作试验下
我是楼主上面三连了回复不了试了一下,我发现LinkedList遍历耗时要比ArrayList数组复制耗时要多得多据我估计,LinkedList删除效率比ArrayList高的索引阀值应该是小于总数的一半的某个值,只有索引比这个阀值小的时候,LinkedList的删除操作效率才有优势前提是都是随机访问
请指正!LinkedList对于随机访问本身就弱
ArrayList的内部数组是一个native method,不同架构效率可能不同
不一定和size一半有关系楼上有个楼都说了,LinkedList删除快针对于remove(Object o)的情况,此情况下两种List都要遍历后才可以删除,LinkedList优势就很明显了对于不同情况采取不同策略才是正道。
删除尾部时,array和link差不多,都很快,是因为array不用移动元素,link可以直接定位到尾部,然后删除。
删除中部时,array比较慢,link非常慢,array每次删除需要移动一半的元素,link定位耗时相当大(每次都要重新定位到中部),由此可见,数据量较大时,定位的开销比移动元素的开销大的多。
删除首部时,array较慢,link很快,array每次删除都要移动所有的元素,而link可以直接定位到首部,直接删除。