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涉及到元素的循环查找
相关推荐
在IT领域,特别是Java编程中,ArrayList和LinkedList是两种非常重要的数据结构,它们都是List接口的实现类。理解这两者的区别对于优化程序性能至关重要。面试官询问这些知识点,旨在评估应聘者的理论基础和实践能力...
在 Java 中,ArrayList 和 LinkedList 是两种常用的集合类,它们各自具有不同的特性和适用场景,主要体现在数据结构、访问效率和操作性能上。 1. 数据结构: - ArrayList 实现了一个动态数组,它内部是一个 Object...
集合(Arraylist,LinkedList)进阶思维导图
在Java编程语言中,`ArrayList`与`LinkedList`都是`List`接口的具体实现类,用于存储元素集合。虽然它们都实现了同样的接口并且提供了相同的基本功能,但在内部实现机制、性能特点以及适用场景等方面存在显著差异。 ...
ArrayList 和 LinkedList 都可以用于实现堆栈、队列或双向队列等数据结构。 Collection 接口是 Java 中最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素(Elements)。Collection 接口...
在Java编程语言中,ArrayList和LinkedList都是集合框架中两种重要的列表实现,它们分别基于不同的数据结构,具有不同的特性和性能特点。以下是对这两个类的详细分析: 1. 数据结构: - ArrayList是基于动态数组的...
2. **线程安全**:ArrayList和LinkedList不是线程安全的,如果在多线程环境中使用,需要手动添加同步机制,或者选择Vector。 3. **内存消耗**:LinkedList比ArrayList和Vector占用更多的内存,因为它需要存储额外的...
今天,我们将深入了解 Java 中的集合类别,包括 ArrayList、Vector、LinkedList 和 Map 等。 ArrayList ArrayList 是一种基于数组的集合类别,它可以存储大量的数据。ArrayList 的特点是:它可以动态地增加或减少...
- **添加和删除**:在LinkedList中,添加和删除元素(尤其是头尾操作)非常高效,因为只需要修改相邻节点的引用即可。 - **访问速度**:LinkedList的按索引访问速度慢,因为需要遍历链表到达指定位置。 - **额外...
在Java编程语言中,ArrayList、LinkedList和Vector是三种常见的动态数组实现,它们都在java.util包中,用于存储和管理对象的集合。这三个类都实现了List接口,提供了多种操作方法,但它们在内部实现和性能特性上有所...
第二个代码示例则比较了从ArrayList和LinkedList中读取100000个元素的时间。在ArrayList中,由于元素存储连续,直接按索引访问几乎瞬间完成。然而,当使用LinkedList时,由于需要从头开始遍历链表,耗时显著增加。 ...
今天,我们将深入探讨这两个集合类的实现原理和比较。 ArrayList 的实现原理 ArrayList 是基于数组实现的,它的底层存储结构是一个数组,用于装载数据。ArrayList 的默认容量是 10,但是这只是数组的容量大小,而...
而在LinkedList中,只需要更改相邻节点的引用即可。因此,对于大量插入操作,LinkedList通常更快。 2. **删除操作**:同样,ArrayList删除元素也需要移动后面的元素,而LinkedList只需调整相邻节点的引用。在频繁...
在Java编程中,ArrayList和LinkedList是两种常见的动态数组,它们都是Java集合框架的一部分,提供了对元素存储和操作的功能。本篇将深入探讨ArrayList和LinkedList的内部实现机制,通过源码分析来揭示它们在性能、...
总结:ArrayList 和 LinkedList 是 Java 中两个常用的集合类,它们的底层实现方式不同,ArrayList 是基于数组实现的,而 LinkedList 是基于链表实现的。理解它们的底层实现方式可以帮助我们更好地使用它们。
通过对比`ArrayList`和`LinkedList`,我们可以看到两种集合类各有优势: - **`ArrayList`**:适用于需要频繁进行随机访问且对插入删除操作次数较少的场景。例如,在处理大量数据并经常需要根据索引进行查询的情况下...
2,随机访问的时候,ArrayList的效率比较高,因为LinkedList要移动指针,而ArrayList是基于 3,索引(index)的数据结构,可以直接映射到。 4,插入、删除数据时,LinkedList的效率比较高,因为ArrayList要移动数据。 ...
本文将通过实例对比 Java 中 ArrayList 和 LinkedList 的实现机制、性能差异、优缺点等方面的区别,帮助读者更好地理解和选择合适的集合实现方式。 一、实现机制 ArrayList 的内部采用数组的方式存储数据,唯一...
本文将深入探讨ArrayList、Vector和LinkedList三种集合类的特点与使用场景,帮助开发者更好地理解它们之间的差异。 #### 一、ArrayList与Vector **1. 存储方式** - **ArrayList** 和 **Vector** 都采用动态数组的...
Java 集合框架中,ArrayList 和 LinkedList 是两种常用的实现类,分别实现了 List 接口。下面我们将详细介绍这两种实现类的方法。 ArrayList ArrayList 是一个基于数组实现的 List 接口实现类,它的底层是使用数组...