主要是复习一下以前学过的知识,也许还能帮助一下刚学习java的新手^-^
所以我也开通了自己的博客
言归正传,网上讲java List的博客也不少,但是我最近看了一本《数据结构与算法分析 java语言描述》,里面对list实现类的讲解还不错,也让我多他们有了更好一点的理解,所以我觉得我还是从这里开始吧,也把自己这方面的知识再巩固一下^-^.
我以前的理解:
ArrayList:提供了List可增长数组的实现,对于随机的get,set调用花费常数时间(即性能更好),但是其对于非末端的add,remove往往花费对数时间(性能比较差)。
Vector:与ArrayList基本一样,但其是线程安全的,所以牺牲一部分性能比ArrayList略差
LinkedList:提供了List的双链表实现,对于随机add,remove往往开销更小,但不易做索引,故随机get,set往往性能更差
实际环境操作:
环境:jdk1.8,Eclipse,以下测试都具有一定的片面性,但我觉得大致能体现一些东西,如有错误,希望指教^-^
1.尾部add操作:
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
LinkedList<Integer> list2 = new LinkedList<>();
Vector<Integer> list3 = new Vector<>();
new Thread(
new Runnable() {
public void run() {
makeList1(list1, 30000);
}
}).start();
new Thread(
new Runnable() {
public void run() {
makeList1(list2, 30000);
}
}).start();
new Thread(
new Runnable() {
public void run() {
makeList1(list3, 30000);
}
}).start();
}
public static List<Integer> makeList1(List<Integer> oo , int n) {
oo.clear();
Long begin = System.currentTimeMillis();
for(int i = 0 ; i < n ; i++) {
oo.add(i); //1
oo.add(0 , i); //2
oo.add(i/2 , i); //3
}
System.out.println(oo.getClass().getName() + ":我是添加方法:" + (System.currentTimeMillis() - begin));
return oo;
}
结果:我发现若在main里面逐一调用,先后顺序对结果有一定影响,故使用多线程调用保证公平
第一次运行:
第二次运行:
第三次运行:
java.util.ArrayList:我是添加方法:32
java.util.ArrayList:我是添加方法:43 java.util.LinkedList:我是添加方法:43
java.util.Vector:我是添加方法:32 java.util.Vector:我是添加方法:43 java.util.Vector:我是添加方法:37
java.util.LinkedList:我是添加方法:29 java.util.LinkedList:我是添加方法:43 java.util.LinkedList:我是添加方法:40
java.util.Vector:我是添加方法:32 java.util.Vector:我是添加方法:43 java.util.Vector:我是添加方法:37
java.util.LinkedList:我是添加方法:29 java.util.LinkedList:我是添加方法:43 java.util.LinkedList:我是添加方法:40
结论:可以看出,对于尾部add操作,三种列表的性能几乎没有相同,也可改变n大小,结果消耗时间几乎为线性增长(为o(N))。当n很大时不能保持o(N),我个人认为是我机器的原因。
2.头部add操作:将1操作中的makeList1方法中1,3注释,消除2的注释
n=2000运行:
n=20000运行:
n=200000运行:
java.util.ArrayList:我是添加方法:2
java.util.Array
List:我是添加方法:49
java.util.ArrayList:我是添加方法:5274
java.util.LinkedList:我是添加方法:1 java.util.LinkedList:我是添加方法:5 java.util.LinkedList:我是添加方法:25
java.util.Vector:我是添加方法:3 java.util.Vector:我是添加方法:47 java.util.Vector:我是添加方法:5285
java.util.LinkedList:我是添加方法:1 java.util.LinkedList:我是添加方法:5 java.util.LinkedList:我是添加方法:25
java.util.Vector:我是添加方法:3 java.util.Vector:我是添加方法:47 java.util.Vector:我是添加方法:5285
结论:对于头部操作LinkedList消耗时间依然保持线性增长(o(N)),但ArrayList,Vector几乎已(o(N^2))增长。
3.中部操作:将makeList1方法中1,2注释,消除3的注释
n=2000运行:
n=20000运行:
n=80000运行:
java.util.ArrayList:我是添加方法:1
java.util.ArrayList:我是添加方法:33 java.util.ArrayList:我是添加方法:667
java.util.Vector:我是添加方法:1 java.util.Vector:我是添加方法:23 java.util.Vector:我是添加方法:670
java.util.LinkedList:我是添加方法:5 java.util.LinkedList:我是添加方法:294 java.util.LinkedList:我是添加方法:27950
java.util.Vector:我是添加方法:1 java.util.Vector:我是添加方法:23 java.util.Vector:我是添加方法:670
java.util.LinkedList:我是添加方法:5 java.util.LinkedList:我是添加方法:294 java.util.LinkedList:我是添加方法:27950
结论:这个结果让我有一些意外,原因应该是在中部add时LinkedList一样要去遍历寻找index,而ArrayList只需把一般元素往后移动。故LinkedList只在前端时性能操作ArrayList;
4.get操作:
<pre name="code" class="java">public static void getList1(List<Integer> oo){
int total = 0;
Long begin = System.currentTimeMillis();
for(int i = 0 ; i < oo.size() ; i++) {
total += oo.get(i);
}
System.out.println(oo.getClass().getName() + ":get运行时间:" + (System.currentTimeMillis() - begin) +"结果" + total);
}
getList1(makeList1(list2, 20000));//run方法里面的函数改为这个
public static void getList1(List<Integer> oo){
int total = 0;
Iterator<Integer> itr = oo.iterator();
Long begin = System.currentTimeMillis();
while(itr.hasNext()){
total += itr.next();
}
System.out.println(oo.getClass().getName() + ":get运行时间:" + (System.currentTimeMillis() - begin) +"结果" + total);
}
n=20000运行: n=60000运行:
java.util.ArrayList:我是添加方法:2
java.util.ArrayList:我是添加方法:10
java.util.ArrayList:get运行时间:2结果199990000 java.util.ArrayList:get运行时间:2结果1799970000
java.util.ArrayList:get运行时间:2结果199990000 java.util.ArrayList:get运行时间:2结果1799970000
java.util.LinkedList:我是添加方法:5
java.util.LinkedList:我是添加方法:6
java.util.LinkedList:get运行时间:176结果199990000
java.util.LinkedList:get运行时间:1534结果1799970000
java.util.Vector:我是添加方法:3
java.util.Vector:我是添加方法:8
java.util.Vector:get运行时间:2结果199990000
java.util.Vector:get运行时间:6结果1799970000
当使用下面的getList1方法时,三者性能几乎误差,有兴趣的可以试试
结论:ArrayList还有Vector花费时间基本保持线性,LinkedList呈o(N^2)增长,set操作与个体操作结果基本一致。
5.遍历remove操作:
public static void removeList1(List<Integer> oo) {
Iterator<Integer> itr = oo.iterator();
Long begin = System.currentTimeMillis();
while(itr.hasNext()){
if(itr.next() % 3 == 0) itr.remove();
}
System.out.println(oo.getClass().getName() + "我是删除方法:" + (System.currentTimeMillis() - begin));
}
</pre><pre name="code" class="java">removeList1(makeList1(list1, 300000));//将run方法内容改成这样
n=60000运行:
n=600000运行:
java.util.LinkedList我是删除方法:9
java.util.LinkedList我是删除方法:17
java.util.ArrayList我是删除方法:134 java.util.ArrayList我是删除方法:3797
java.util.Vector我是删除方法:139 java.util.Vector我是删除方法:3802
java.util.ArrayList我是删除方法:134 java.util.ArrayList我是删除方法:3797
java.util.Vector我是删除方法:139 java.util.Vector我是删除方法:3802
结论:LinkedList操作时间保持线性,Vector,ArrayList呈O(N^2)
6.随机remove操作:
public static void removeList1(List<Integer> oo) {
int n = oo.size()/2 ;
Long begin = System.currentTimeMillis();
for(int i = n; n > 0 ; n-- ){
oo.remove(i);
}
System.out.println(oo.getClass().getName() + "我是删除方法:" + (System.currentTimeMillis() - begin));
}
n=3000运行: n=9000运行:
java.util.ArrayList我是删除方法:1
java.util.ArrayList我是删除方法:4
java.util.Vector我是删除方法:1 java.util.Vector我是删除方法:3
java.util.LinkedList我是删除方法:5 java.util.LinkedList我是删除方法:20
java.util.Vector我是删除方法:1 java.util.Vector我是删除方法:3
java.util.LinkedList我是删除方法:5 java.util.LinkedList我是删除方法:20
结论:此时LinkedList性能并不如ArrayList,Vector