`
wuliHjz123
  • 浏览: 5371 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

集合中ArrayList和LinkedList比较

 
阅读更多

ArrayList和LinkedList比较
从尾部添加效率比较
public void TestArrayAndLinkedListAdd(){
 List<Integer> list1 = new ArrayList<Integer>();
 List<Integer> list2 = new LinkedList<Integer>();

 long lss2 = System.currentTimeMillis();
 for(int i = 0; i < 1000000; i ++){
  list2.add(i);
 }
 long lse2 = System.currentTimeMillis();
 long li2 = lse2 - lss2;
 System.out.println("LinkedList:---" + li2);

 long lss1 = System.currentTimeMillis();
 for(int i = 0; i < 1000000; i ++){
  list1.add(i);
 }
 long lse1 = System.currentTimeMillis();
 long li1 = lse1 - lss1;
 System.out.println("ArrayList:---" + li1);
 
}
LinkedList:---619
ArrayList:---179
可以看出ArrayList效率高于LinkedList,分析源码
ArrayList中add方法
public boolean add(E e) {
 ensureCapacityInternal(size + 1);  // Increments modCount!!
 elementData[size++] = e;
 return true;
}
//检查容量
private void ensureCapacityInternal(int minCapacity) {
 if (elementData == EMPTY_ELEMENTDATA) {
  minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
 }

 ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
 modCount++;

 // 如果容量大于数组长度,扩容
 if (minCapacity - elementData.length > 0)
  grow(minCapacity);
}
private void grow(int minCapacity) {
 // overflow-conscious code
 int oldCapacity = elementData.length;
 int newCapacity = oldCapacity + (oldCapacity >> 1); //新的容量为原容量的1.5倍
 if (newCapacity - minCapacity < 0)  //新的容量小于最小的容量
  newCapacity = minCapacity; //新容量等于最小的容量
 if (newCapacity - MAX_ARRAY_SIZE > 0) //新容量大于(2的31次方-8)
  newCapacity = hugeCapacity(minCapacity);
 // minCapacity is usually close to size, so this is a win:
 //将当前数组copy指定长度的新数组中 Arrays.copyOf底层调用的是System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
 elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
 //假如minCapacity大于Integer的最大数限制,加一时则变成负数,minCapacity为负数,抛出栈溢出错误
 if (minCapacity < 0) // overflow
  throw new OutOfMemoryError();
 //如果没有返回Integer最大值或者最大值-8
 return (minCapacity > MAX_ARRAY_SIZE) ?
 Integer.MAX_VALUE :
 MAX_ARRAY_SIZE;
}

LinkedList中的add方法
public boolean add(E e) {
 linkLast(e);
 return true; //不需要去掉重复,默认每次添加都是成功的
}
//将元素添加在链表的后面
void linkLast(E e) {
 final Node<E> l = last;
 final Node<E> newNode = new Node<>(l, e, null); //新建一个Node对象
 last = newNode;
 if (l == null)
  first = newNode;
 else
  l.next = newNode;
 size++;
 modCount++;
}
结论:从尾部直接添加,虽然ArrayList每次添加时都会检查容量,并且扩容,但是LinkedList每次添加都会新建一个Node对象,所以速度慢于ArrayList

从在中间添加添加效率比较
public void TestArrayAndLinkedList(){
 List<Integer> list1 = new ArrayList<Integer>();
 List<Integer> list2 = new LinkedList<Integer>();
 for(int i = 0; i < 100000; i ++){
  list1.add(i);
  list2.add(i);
 }
 int random1 = (int)(Math.random()*1000);//300;
 int random2 = (int)(Math.random()*10000);//9000;
 long lss1 = System.currentTimeMillis();
 for(int i = random1; i < random2; i ++){
  //list1.remove((Integer)i);
  list1.add(i, i);
 }
 long lse1 = System.currentTimeMillis();
 long li1 = lse1 - lss1;
 System.out.println("ArrayList:---" + li1);
 long lss2 = System.currentTimeMillis();
 for(int i = random1; i < random2; i ++){
  //list2.remove((Integer)i);
  list2.add(i, i);
 }
 long lse2 = System.currentTimeMillis();
 long li2 = lse2 - lss2;
 System.out.println("LinkedList:---" + li2);
 
}
ArrayList:---91
LinkedList:---6
试验LinkedList效率高于ArrayList
查看源码:
ArrayList中
public void add(int index, E element) {
 rangeCheckForAdd(index);
 //检查并且扩容
 ensureCapacityInternal(size + 1);  // Increments modCount!!
 //将elementData中index后的元素copy到elementData的index+1,就是index后的所有元素后移一位
 System.arraycopy(elementData, index, elementData, index + 1,
   size - index);
 elementData[index] = element;
 size++;
}
LinkedList中
public void add(int index, E element) {
 checkPositionIndex(index);

 if (index == size)
  linkLast(element);
 else
  linkBefore(element, node(index)); //node(index) 查询该位置的元素,将element添加到index位置元素的前面
}
结论:实际上上诉示例中修改集合的容量大小和添加的次数,会发现在50000个容量且插入次数为1000次以上的操作LinkedList的速度才会大于ArrayList,
但是在这个数量级之下ArrayList的速度是大于LinkedList的

get效率比较
public void TestArrayAndLinkedList(){
 List<Integer> list1 = new ArrayList<Integer>();
 List<Integer> list2 = new LinkedList<Integer>();
 for(int i = 0; i < 100000; i ++){
  list1.add(i);
  list2.add(i);
 }
 int random1 = (int)(Math.random()*1000);//300;
 int random2 = (int)(Math.random()*10000);//9000;
 long lss1 = System.currentTimeMillis();
 for(int i = random1; i < random2; i ++){
  //list1.remove((Integer)i);
  list1.get(i);
 }
 long lse1 = System.currentTimeMillis();
 long li1 = lse1 - lss1;
 System.out.println("arrayList:---" + li1);
 long lss2 = System.currentTimeMillis();
 for(int i = random1; i < random2; i ++){
  //list2.remove((Integer)i);
  list2.get(i);
 }
 long lse2 = System.currentTimeMillis();
 long li2 = lse2 - lss2;
 System.out.println("LinkedList:---" + li2);
 
}
ArrayList:---1
LinkedList:---159
可以看出ArrayList效率高于LinkedList,分析源码
ArrayList中get(int index)方法
public E get(int index) {
 rangeCheck(index); //检查下标是否超出范围

 return elementData(index);//通过下标获取
}
LinkedList中get(int index)方法
public E get(int index) {
 checkElementIndex(index);
 return node(index).item;
}
Node<E> node(int index) {
 // assert isElementIndex(index);

 if (index < (size >> 1)) { //如果坐标小于当前集合大小的一半 从头开始循环查询直到index
  Node<E> x = first;
  for (int i = 0; i < index; i++)
   x = x.next;
  return x;
 } else {
  Node<E> x = last; //如果坐标大于当前集合大小的一半 从尾部开始循环查询直到index
  for (int i = size - 1; i > index; i--)
   x = x.prev;
  return x;
 }
}
结论:上述是通过下标获取元素,很明显ArrayList优势远高于LinkedList

remove(Object o)直接删除元素效率比较
public void TestArrayAndLinkedList(){
 List<Integer> list1 = new ArrayList<Integer>();
 List<Integer> list2 = new LinkedList<Integer>();
 for(int i = 0; i < 1000; i ++){
  list1.add(i);
  list2.add(i);
 }
 int random1 = 0;//(int)(Math.random()*1000);//300;
 int random2 = 200;//(int)(Math.random()*10000);//9000;
 
 long lss1 = System.currentTimeMillis();
 for(int i = random1; i < random2; i ++){
  list1.remove((Integer)i);
  //list1.add(i, i);
 }
 long lse1 = System.currentTimeMillis();
 long li1 = lse1 - lss1;
 System.out.println("ArrayList:---" + li1);
 
 long lss2 = System.currentTimeMillis();
 for(int i = random1; i < random2; i ++){
  list2.remove((Integer)i);
  //list2.add(i, i);
 }
 long lse2 = System.currentTimeMillis();
 long li2 = lse2 - lss2;
 System.out.println("LinkedList:---" + li2);
 
}
改变集合容量和删除次数,发现数量级在1000以下,删除次数在50左右,效率的差不多的,但是LinkedList的效率还是优于ArrayList
查看源码:
ArrayList的remove(Object o)
//以元素作为参数时,ArrayList会查找元素,然后删除,且从头查找只删除一次,所以不能一次删除重复元素
public boolean remove(Object o) {
 if (o == null) {
  for (int index = 0; index < size; index++)
   if (elementData[index] == null) {
    fastRemove(index);
    return true;
   }
 } else {
   for (int index = 0; index < size; index++)
   if (o.equals(elementData[index])) {
    fastRemove(index);
    return true;
   }
 }
 return false;
}
private void fastRemove(int index) {
 modCount++;
 int numMoved = size - index - 1; //总共需要移动这么多元素
 if (numMoved > 0)
  //将index+1到size的元素移到index到size-1下标上
  System.arraycopy(elementData, index+1, elementData, index,
       numMoved);
 //将数组最后一个元素置为null,等待GC回收 size减一
 elementData[--size] = null; // clear to let GC do its work
}

LinkedList的remove(Object o)
//从第一个查找,找到后执行删除(unlink)
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;
}
//将该元素的上一个元素的下一个指向该元素的下一个元素,该元素的下一个元素的上一个指向该元素的上一个元素
E unlink(Node<E> x) {
 // assert x != null;
 final E element = x.item;
 final Node<E> next = x.next;
 final Node<E> prev = x.prev;

 if (prev == null) {
  first = next;
 } else {
  prev.next = next;
  x.prev = null;
 }

 if (next == null) {
  last = prev;
 } else {
  next.prev = prev;
  x.next = null;
 }

 x.item = null; //该元素中的所有属性置为null
 size--; //size减一 记录集合元素的数量
 modCount++; //modCount是AbstractList中定义的成员变量,是记录list在结构上修改的次数???不知道解释的对不对
 return element;
}
结论:根据元素删除,LinkedList的效率优于ArrayList,因为ArrayList需要循环查找和位移,而linkedList只在查找上消耗时间

remove(int index)根据下标删除元素效率比较
public void TestArrayAndLinkedList(){
 List<Integer> list1 = new ArrayList<Integer>();
 List<Integer> list2 = new LinkedList<Integer>();
 for(int i = 0; i < 100000; i ++){
  list1.add(i);
  list2.add(i);
 }
 int random1 = 2000;//(int)(Math.random()*1000);//300;
 int random2 = 9000;//(int)(Math.random()*10000);//9000;
 
 long lss1 = System.currentTimeMillis();
 for(int i = random1; i < random2; i ++){
  list1.remove(i);
  //list1.add(i, i);
 }
 long lse1 = System.currentTimeMillis();
 long li1 = lse1 - lss1;
 System.out.println("ArrayList:---" + li1);
 
 long lss2 = System.currentTimeMillis();
 for(int i = random1; i < random2; i ++){
  list2.remove(i);
  //list2.add(i, i);
 }
 long lse2 = System.currentTimeMillis();
 long li2 = lse2 - lss2;
 System.out.println("LinkedList:---" + li2);
 
}
根据坐标删除,ArrayList的速度要快于linkedList
源码分析:
ArrayList的remove(int index)
//源码中直接根据坐标进行位移
public E remove(int index) {
 rangeCheck(index);

 modCount++;
 E oldValue = elementData(index);

 int numMoved = size - index - 1;
 if (numMoved > 0)
     System.arraycopy(elementData, index+1, elementData, index,
        numMoved);
 elementData[--size] = null; // clear to let GC do its work

 return oldValue;
}

linkedList的remove(int index)
public E remove(int index) {
 checkElementIndex(index); //判断index是否存在集合的正常范围,超过报IndexOutOfBoundsException,调用下面的isElementIndex方法
 return unlink(node(index)); //node(index)根据index查询元素,上面有说明
}
private boolean isElementIndex(int index) {
 return index >= 0 && index < size;
}

结论:根据下标删除ArrayList的速度要快于linkedList,linkedList涉及到元素的循环查找

分享到:
评论

相关推荐

    ArrayList和Linkedlist1

    在IT领域,特别是Java编程中,ArrayList和LinkedList是两种非常重要的数据结构,它们都是List接口的实现类。理解这两者的区别对于优化程序性能至关重要。面试官询问这些知识点,旨在评估应聘者的理论基础和实践能力...

    Java中ArrayList和LinkedList区别 时间复杂度 与空间复杂度1

    在 Java 中,ArrayList 和 LinkedList 是两种常用的集合类,它们各自具有不同的特性和适用场景,主要体现在数据结构、访问效率和操作性能上。 1. 数据结构: - ArrayList 实现了一个动态数组,它内部是一个 Object...

    集合(Arraylist,LinkedList)进阶思维导图

    集合(Arraylist,LinkedList)进阶思维导图

    关于arraylist和linkedList的区别

    在Java编程语言中,`ArrayList`与`LinkedList`都是`List`接口的具体实现类,用于存储元素集合。虽然它们都实现了同样的接口并且提供了相同的基本功能,但在内部实现机制、性能特点以及适用场景等方面存在显著差异。 ...

    ArrayList LinkedList Vector区别

    ArrayList 和 LinkedList 都可以用于实现堆栈、队列或双向队列等数据结构。 Collection 接口是 Java 中最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素(Elements)。Collection 接口...

    Java中ArrayList和LinkedList区别

    在Java编程语言中,ArrayList和LinkedList都是集合框架中两种重要的列表实现,它们分别基于不同的数据结构,具有不同的特性和性能特点。以下是对这两个类的详细分析: 1. 数据结构: - ArrayList是基于动态数组的...

    ArrayList LinkedList Vector性能对比

    2. **线程安全**:ArrayList和LinkedList不是线程安全的,如果在多线程环境中使用,需要手动添加同步机制,或者选择Vector。 3. **内存消耗**:LinkedList比ArrayList和Vector占用更多的内存,因为它需要存储额外的...

    Java 各种集合的区别ArrayList Vector LinkedList map区别

    今天,我们将深入了解 Java 中的集合类别,包括 ArrayList、Vector、LinkedList 和 Map 等。 ArrayList ArrayList 是一种基于数组的集合类别,它可以存储大量的数据。ArrayList 的特点是:它可以动态地增加或减少...

    比较ArrayList、LinkedList、Vector1

    - **添加和删除**:在LinkedList中,添加和删除元素(尤其是头尾操作)非常高效,因为只需要修改相邻节点的引用即可。 - **访问速度**:LinkedList的按索引访问速度慢,因为需要遍历链表到达指定位置。 - **额外...

    ArrayList LinkedList Vector性能测试

    在Java编程语言中,ArrayList、LinkedList和Vector是三种常见的动态数组实现,它们都在java.util包中,用于存储和管理对象的集合。这三个类都实现了List接口,提供了多种操作方法,但它们在内部实现和性能特性上有所...

    合理运用ArrayList与LinkedList

    第二个代码示例则比较了从ArrayList和LinkedList中读取100000个元素的时间。在ArrayList中,由于元素存储连续,直接按索引访问几乎瞬间完成。然而,当使用LinkedList时,由于需要从头开始遍历链表,耗时显著增加。 ...

    当面试官问我ArrayList和LinkedList哪个更占空间时,我这么答让他眼前一亮

    今天,我们将深入探讨这两个集合类的实现原理和比较。 ArrayList 的实现原理 ArrayList 是基于数组实现的,它的底层存储结构是一个数组,用于装载数据。ArrayList 的默认容量是 10,但是这只是数组的容量大小,而...

    arraylist-linkedlist-test.zip

    而在LinkedList中,只需要更改相邻节点的引用即可。因此,对于大量插入操作,LinkedList通常更快。 2. **删除操作**:同样,ArrayList删除元素也需要移动后面的元素,而LinkedList只需调整相邻节点的引用。在频繁...

    ArrayList-LinkedList-源码.rar

    在Java编程中,ArrayList和LinkedList是两种常见的动态数组,它们都是Java集合框架的一部分,提供了对元素存储和操作的功能。本篇将深入探讨ArrayList和LinkedList的内部实现机制,通过源码分析来揭示它们在性能、...

    对ArrayList和LinkedList底层实现原理详解

    总结:ArrayList 和 LinkedList 是 Java 中两个常用的集合类,它们的底层实现方式不同,ArrayList 是基于数组实现的,而 LinkedList 是基于链表实现的。理解它们的底层实现方式可以帮助我们更好地使用它们。

    ArrayList 和LinkedList各自的特点是什么

    通过对比`ArrayList`和`LinkedList`,我们可以看到两种集合类各有优势: - **`ArrayList`**:适用于需要频繁进行随机访问且对插入删除操作次数较少的场景。例如,在处理大量数据并经常需要根据索引进行查询的情况下...

    Arraylist与LinkedList区别

    2,随机访问的时候,ArrayList的效率比较高,因为LinkedList要移动指针,而ArrayList是基于 3,索引(index)的数据结构,可以直接映射到。 4,插入、删除数据时,LinkedList的效率比较高,因为ArrayList要移动数据。 ...

    java中ArrayList与LinkedList对比详情

    本文将通过实例对比 Java 中 ArrayList 和 LinkedList 的实现机制、性能差异、优缺点等方面的区别,帮助读者更好地理解和选择合适的集合实现方式。 一、实现机制 ArrayList 的内部采用数组的方式存储数据,唯一...

    ArrayList Vector LinkedList 区别与用法.

    本文将深入探讨ArrayList、Vector和LinkedList三种集合类的特点与使用场景,帮助开发者更好地理解它们之间的差异。 #### 一、ArrayList与Vector **1. 存储方式** - **ArrayList** 和 **Vector** 都采用动态数组的...

    java 集合之实现类ArrayList和LinkedList的方法

    Java 集合框架中,ArrayList 和 LinkedList 是两种常用的实现类,分别实现了 List 接口。下面我们将详细介绍这两种实现类的方法。 ArrayList ArrayList 是一个基于数组实现的 List 接口实现类,它的底层是使用数组...

Global site tag (gtag.js) - Google Analytics