Arraylist和Linkedlist的区别以及性能分析详解

                              Arraylist和Linkedlist的区别以及性能分析

Arraylistlist和Linkedlist的区别:

1、Arraylistlist是基于动态数组实现的数据结构。Linkedlist是基于双向链表实现的数据结构。

2、Arraylistlist对数据的读取修改的效率较Linkedlist快。因为Arraylistlist可以根据索引值直接定位到对应的元素。

而Linkedlist需要循环找到对应的元素。

3、对于插入和删除元素来说,插入有序的Arraylistlist相对于Linkedlist较慢(当数据量小的时候)。

Arraylistlist和Linkedlist的性能测试:

查找与修改:对于查找和修改来说,效率是差不多的。因为找到之后就可以进行修改。这时候要分情况进行讨论。

1、Arraylistlist采用下标方式找到元素,Linkedlist采用遍历的方式找到元素。对于Arraylistlist,可以根据下标查找和修改元

素,耗费的时间比较微小,几乎就是微秒级的操作。而Linkedlist只能通过遍历找到对应的元素。所以Arraylistlist的效率在

这种情况较高。

2、两种数据结构都采用遍历的方式找到元素,这种情况下Arraylist的效率高。因为要按顺序索引,而Arraylistlist各个元

素存储地址是连续的,所以查找效率快。

package MM;

import java.util.ArrayList;
import java.util.LinkedList;

public class TestArraylistandLinklist {

	public static void main(String[] args) {
		ArrayList<Integer> a=new ArrayList<>(1000);
		LinkedList<Integer>b=new LinkedList<>();
		for(int i=0;i<100000;i++) {
			a.add(i);
			b.add(i);
		}
		find(1000, a);
		find(1000, b);
	}
	public static void find(Integer a,ArrayList<Integer> b) {
		long begin=System.currentTimeMillis();
		for(int i=0;i<b.size();i++) {
			if(b.get(i)==a) {
				System.out.println(a);
			}
		}
		long end=System.currentTimeMillis();
		System.out.println("ArrayList查找固定值的数据花费的时间为:"+(end-begin));
	}
	public static void find(Integer a,LinkedList<Integer> b) {
		long begin=System.currentTimeMillis();
		for(int i=0;i<b.size();i++) {
			if(b.get(i)==a) {
				System.out.println(a);
			}
		}
		long end=System.currentTimeMillis();
		System.out.println("LinkedList查找固定值的数据花费的时间为:"+(end-begin));
	}
}

可以看到如果是查找操作的话,Arraylist是很好的选择。

增加:

对于同时插入数据,插入数据量小的时候Linkedlist效率高一些,但是当插入的数据量多的时候,那么Arraylist的效率

是高的。这种结果是不是出乎意料。经过大量测试,那个临界的范围大概是45万。当低于45万的时候,Linkedlist的

插入效率高,当插入数据多于45万的时候,Arraylist的效率高。我们来看下测试的代码。

插入数据在45万:

package MM;

import java.util.ArrayList;
import java.util.LinkedList;

public class TestArraylistandLinklist {

	public static void main(String[] args) {
		ArrayList<Integer> a=new ArrayList<>();
		LinkedList<Integer>b=new LinkedList<>();
		insert(a);
		insert(b);
	}
	public static void insert(ArrayList<Integer> a) {
		long begin=System.currentTimeMillis();
		for(int i=0;i<450000;i++) {
			int j=(int) (Math.random()*1000);
			a.add(j);
		}
		long end=System.currentTimeMillis();
		System.out.println("ArrayList插入1000000条数据花费的时间为:"+(end-begin));
	}
	public static void insert(LinkedList<Integer> a) {
		long begin=System.currentTimeMillis();
		for(int i=0;i<450000;i++) {
			int j=(int) (Math.random()*1000);
			a.add(j);
		}
		long end=System.currentTimeMillis();
		System.out.println("LinkedList插入100000条数据花费的时间为:"+(end-begin));
	}

}

测试结果:

插入数据在50万以上:

package MM;

import java.util.ArrayList;
import java.util.LinkedList;

public class TestArraylistandLinklist {

	public static void main(String[] args) {
		ArrayList<Integer> a=new ArrayList<>();
		LinkedList<Integer>b=new LinkedList<>();
		insert(a);
		insert(b);
	}
	public static void insert(ArrayList<Integer> a) {
		long begin=System.currentTimeMillis();
		for(int i=0;i<500000;i++) {
			int j=(int) (Math.random()*1000);
			a.add(j);
		}
		long end=System.currentTimeMillis();
		System.out.println("ArrayList插入1000000条数据花费的时间为:"+(end-begin));
	}
	public static void insert(LinkedList<Integer> a) {
		long begin=System.currentTimeMillis();
		for(int i=0;i<500000;i++) {
			int j=(int) (Math.random()*1000);
			a.add(j);
		}
		long end=System.currentTimeMillis();
		System.out.println("LinkedList插入100000条数据花费的时间为:"+(end-begin));
	}

}

在50万之后发生了质的变化。Arraylist的插入效率是Linkedlist的两倍多。

我们先来看下两种数据结构的add方法实现源码。

Arraylist:

Linkedlist:

Linkedlist的插入是new一个结点。Arraylist的插入是在现有的空间上,没有空闲的空间。Arraylist会开辟一段新的连续的

空间,大小为原来大小的1.5倍。

当数据量小的时候,Arraylist的时间开销主要花费在复制原来的数组,这时候Linklist的插入效率是快的。

当数据量大的时候,Arraylist开辟的连续的空间自然也就大了。就不需要频繁的复制数组到新的空间。这样在写数据的

时候就可以很容易的定位到要写的位置。而Linklist为了保证能够有指向下一结点的的空间,在插入数据量大的时候需

要去别的扇区开辟新空间,这种磁头的机械运动会花费大量的时间。所以这种情况下Arraylist的效率高。

删除:

在这里我们讨论删除的元素是两种数据结构自带的remove函数的性能。先来看下测试的结果:

package MM;

import java.util.ArrayList;
import java.util.LinkedList;

public class TestArraylistandLinklist {

	public static void main(String[] args) {
		ArrayList<Integer> a=new ArrayList<>();
		LinkedList<Integer>b=new LinkedList<>();
		for(int i=0;i<500000;i++) {
			int j=(int) (Math.random()*1000);
			a.add(j);
			b.add(j);
		}
		remove(a, 300000);
		remove(b, 300000);
	}
	public static void remove(ArrayList<Integer> a,int index) {
		long begin=System.currentTimeMillis();
		a.remove(index);
		long end=System.currentTimeMillis();
		System.out.println("ArrayList删除一个固定位置的元素花费时间为"+(end-begin));
	}
	public static void remove(LinkedList<Integer> a,int index) {
		long begin=System.currentTimeMillis();
		a.remove(index);
		long end=System.currentTimeMillis();
		System.out.println("LinkedList删除一个固定位置的元素花费时间为"+(end-begin));
	}
}

Arraylist的删除操作是微秒级的,而Linkedlist需要两毫秒的时间。对于计算机来说,两毫秒是占用cpu时间比较多的情况。

先来分析一下Arraylist的remove函数的源码:

Arraylist的remove函数首先判断要删除元素的下标是否越界。然后记录下要删除元素的前面的元素在numMoved里,

然后调用本地方法arraycopy函数复制要删除元素的前面的元素和要删除元素的后面的元素到新的数组中,返回数组。

整个过程花费的时间主要在数组copy上,但是开还是比较小的。

先来分析一下Arraylist的remove函数的源码:

Linkedlist的remove函数也是先判断下标是否越界,没有越界之后。执行unlink函数,把找到的值对应的结点从整个链删除,

只是简单的改变指向,耗费的时间只是微妙级的。但是找到这个结点具体的位置需要通过搜索来找到。即使采用较快的

搜索方法,例如二分搜索,也是需要一定的时间开销的。而Linkedlist因为地理位置连续可以直接定位到。所以性能比不上

Arraylistlist。

展开阅读全文

没有更多推荐了,返回首页