Java 在列表中间插入的情况下,LIKEDLIST真的比ARARYLIST快吗?
-Java 在列表中间插入的情况下,LIKEDLIST真的比ARARYLIST快吗?,java,collections,Java,Collections,-LinkedList和ArrayList之间有什么区别?何时最好使用链接列表 我认为每个Java开发人员在采访中都至少听过一次这个问题 如果希望能够在列表中间插入项目,请使用链接表。 这是这个问题的常见答案。大家都知道。每次您询问列表实现之间的差异时,您都会得到如下答案: 我应该什么时候使用LinkedList?何时需要在元素之间或在开始时高效地删除 忘了提到插入成本。在LinkedList中,一旦找到正确的位置,插入成本将O(1),而在ArrayList中,插入成本将上升到O(n)-所有元
LinkedList
和ArrayList
之间有什么区别?何时最好使用链接列表
我认为每个Java开发人员在采访中都至少听过一次这个问题
如果希望能够在列表中间插入项目,请使用链接表。
这是这个问题的常见答案。大家都知道。每次您询问列表实现之间的差异时,您都会得到如下答案:
我应该什么时候使用LinkedList?何时需要在元素之间或在开始时高效地删除
忘了提到插入成本。在LinkedList中,一旦找到正确的位置,插入成本将O(1)
,而在ArrayList中,插入成本将上升到O(n)
-所有元素必须移动到插入点之外
当您希望能够将项目插入列表中间(例如优先级队列)时,链接列表优于数组。
ArrayList速度较慢,因为它需要复制阵列的一部分,以便删除已变为空闲的插槽。LinkedList只需操纵几个引用
还有更多
但是你有没有试过自己复制它?我昨天试过了,结果如下:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class Test {
public static void main(String... args) {
final int MAX_VAL = 10000;
List<Integer> linkedList = new LinkedList<Integer>();
List<Integer> arrayList = new ArrayList<Integer>();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
arrayList.add(i);
}
long time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(MAX_VAL/2, i);
}
System.out.println("LL time: " + (System.nanoTime() - time));
time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
arrayList.add(MAX_VAL/2, i);
}
System.out.println("AL time: " + (System.nanoTime() - time));
}
}
import java.util.ArrayList;
导入java.util.LinkedList;
导入java.util.List;
公开课考试{
公共静态void main(字符串…参数){
最终整数最大值=10000;
List linkedList=新建linkedList();
List arrayList=新建arrayList();
对于(int i=0;i
输出:
LL时间:114098106
美国时间:2412189
那是什么呢?为什么LinkedList如此糟糕?也许我们应该尝试删除操作而不是添加?好的,让我们试试:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class Test {
public static void main(String... args) {
final int MAX_VAL = 10000;
List<Integer> linkedList = new LinkedList<Integer>();
List<Integer> arrayList = new ArrayList<Integer>();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
arrayList.add(i);
}
long time = System.nanoTime();
for(int i = 0; i < MAX_VAL/2; i++) {
linkedList.remove(MAX_VAL/2);
}
System.out.println("LL time: " + (System.nanoTime() - time));
time = System.nanoTime();
for(int i = 0; i < MAX_VAL/2; i++) {
arrayList.remove(MAX_VAL/2);
}
System.out.println("AL time: " + (System.nanoTime() - time));
}
}
import java.util.ArrayList;
导入java.util.LinkedList;
导入java.util.List;
公开课考试{
公共静态void main(字符串…参数){
最终整数最大值=10000;
List linkedList=新建linkedList();
List arrayList=新建arrayList();
对于(int i=0;i
输出:
LL时间:27581163
美国时间:3103051
哦,ArrayList仍然比LinkedList快。原因是什么?这个神话破灭了吗?也许我错了
破坏
不是真的。这里
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(MAX_VAL/2, i);
}
for(int i=0;i
您不只是插入项目;每次从一开始迭代到i
,您都要为此付出代价。当然,这是O(i)
另一方面,在您真正了解中间列表插入的性能优势之前,列表必须非常大System.arraycopy
是一个非常快速的操作,在另一端,每次插入到LinkedList
中都需要分配一个节点实例
总之,ArrayList
对于99%或更多的实际案例是一个更好的选择,利用LinkedList
的狭隘优势需要非常小心
关于JVM微基准标记的一般说明
我还应该警告您,您的基准测试代码存在严重缺陷。在JVM上进行微博客共享时,需要注意的事情很多,例如:
- 始终对代码进行预热,让JIT编译器处理它李>
- 由于准确性/精确性问题,在解释
结果时要非常小心。使读数至少增加到毫秒(百万纳秒),以确保可靠性李>nanoTime
- 控制垃圾收集器的虚假副作用李>
- 等等
因此,建议使用现成的微基准标记框架,例如。必须注意以下简单的评测:
- 垃圾收集可能在不可预测的时间发生,从而减慢了速度 不可预测的部分李>
- JRE在第一次启动时速度较慢,之后会“预热”
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
public class Test {
public static void main(String... args) {
final int MAX_VAL = 10000;
List<Integer> linkedList = new LinkedList<Integer>();
List<Integer> arrayList = new ArrayList<Integer>();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
arrayList.add(i);
}
long time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(MAX_VAL/2, i);
}
System.out.println("LL time:\t" + (System.nanoTime() - time));
time = System.nanoTime();
for(int i = 0; i < MAX_VAL; i++) {
arrayList.add(MAX_VAL/2, i);
}
System.out.println("AL time:\t" + (System.nanoTime() - time));
//Reset the lists
linkedList = new LinkedList<Integer>();
arrayList = new ArrayList<Integer>();
for(int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
arrayList.add(i);
}
time = System.nanoTime();
ListIterator<Integer> li = linkedList.listIterator(MAX_VAL/2);
for(int i = 0; i < MAX_VAL; i++) {
li.add(i);
}
System.out.println("LL iterator:\t" + (System.nanoTime() - time));
time = System.nanoTime();
ListIterator<Integer> ali = arrayList.listIterator(MAX_VAL/2);
for(int i = 0; i < MAX_VAL; i++) {
ali.add(i);
}
System.out.println("AL iterator:\t" + (System.nanoTime() - time));
}
}
因为ArrayList按顺序存储值 因此 1:更快地添加值(只需添加最后一个索引中的值) 2:更新或删除速度较慢(将有
LL time: 237819474
AL time: 31410507
LL iterator: 5423172
AL iterator: 23975798
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;
public class TestList {
public static void main(String... args) {
final int MAX_VAL = 10000;
int[] currentIndex = {0, 0, 0, 0};
int[] remaining = {50, 50, 50, 50};
int[][] sequence = new int[4][50];
while (keepWorking(remaining)) { //run 50 tests for each case at random
int currentMethod = chooseMethod(remaining); //choose case. Probability is higher for tests with less trials
switch (currentMethod) { //run a test based on the choice
case 0:
sequence[currentMethod][currentIndex[currentMethod]] = getLL(MAX_VAL);
break;
case 1:
sequence[currentMethod][currentIndex[currentMethod]] = getAL(MAX_VAL);
break;
case 2:
sequence[currentMethod][currentIndex[currentMethod]] = getLLIt(MAX_VAL);
break;
default:
sequence[currentMethod][currentIndex[currentMethod]] = getALIt(MAX_VAL);
break;
}
remaining[currentMethod]--;
currentIndex[currentMethod]++;
}
for (int[] ar : sequence) {
Arrays.sort(ar);
}
System.out.println("Time (us\nLL \tAL\tLL incr\t AL incr");
for (int i = 0; i < sequence[0].length; i++) {
System.out.println(sequence[0][i] + "\t" + sequence[1][i] + "\t" + sequence[2][i] + "\t" + sequence[3][i]);
}
System.out.println("\nTime normalized to fastest run of a method\nLL\tAL\tLL incr\t AL incr");
for (int i = 0; i < sequence[0].length; i++) {
System.out.print(i);
for (int j = 0; j < sequence.length; j++) { //to 4
int a = sequence[j][i] / (sequence[j][0]/100); //to keep result within the scope of int
System.out.print("\t" + a);
}
System.out.println();
}
}
public static boolean keepWorking(int[] remaining) {
for (int i = 0; i < remaining.length; i++) {
if (remaining[i] > 0) {
return true;
}
}
return false;
}
public static int chooseMethod(int[] rem) {
int[] bins = new int[rem.length];
for (int i = 0; i < rem.length; i++) {
for (int j = i; j < rem.length; j++) {
bins[j] += rem[i];
}
}
int randomNum = new Random().nextInt(bins[rem.length - 1]);
for (int i = 0; i < bins.length; i++) {
if (randomNum < bins[i]) {
return i;
}
}
return -1;
}
public static int getLL(int MAX_VAL) {
List<Integer> linkedList = new LinkedList<>();
for (int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
}
long time = System.nanoTime();
for (int i = 0; i < MAX_VAL; i++) {
linkedList.add(MAX_VAL / 2, i);
}
return (int) (System.nanoTime() - time)/1000;
}
public static int getAL(int MAX_VAL) {
List<Integer> arrayList = new ArrayList<>(MAX_VAL);
for (int i = 0; i < MAX_VAL; i++) {
arrayList.add(i);
}
long time = System.nanoTime();
for (int i = 0; i < MAX_VAL; i++) {
arrayList.add(MAX_VAL / 2, i);
}
return (int) (System.nanoTime() - time)/1000;
}
public static int getLLIt(int MAX_VAL) {
List<Integer> linkedList = new LinkedList<>();
for (int i = 0; i < MAX_VAL; i++) {
linkedList.add(i);
}
long time = System.nanoTime();
ListIterator<Integer> li = linkedList.listIterator(MAX_VAL / 2);
for (int i = 0; i < MAX_VAL; i++) {
li.add(i);
}
return (int) (System.nanoTime() - time)/1000;
}
public static int getALIt(int MAX_VAL) {
List<Integer> arrayList = new ArrayList<>(MAX_VAL);
for (int i = 0; i < MAX_VAL; i++) {
arrayList.add(i);
}
long time = System.nanoTime();
ListIterator<Integer> ali = arrayList.listIterator(MAX_VAL / 2);
for (int i = 0; i < MAX_VAL; i++) {
ali.add(i);
}
return (int) (System.nanoTime() - time)/1000;
}
}