Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java LinkedList与ArrayList在维护有序列表方面的性能_Java_Sorting_Arraylist_Linked List - Fatal编程技术网

Java LinkedList与ArrayList在维护有序列表方面的性能

Java LinkedList与ArrayList在维护有序列表方面的性能,java,sorting,arraylist,linked-list,Java,Sorting,Arraylist,Linked List,我想维护一个大小为的有序列表,在LinkedList上调用sort()会破坏性能,因为默认实现了List.sort()将列表转换为数组进行排序。在很少的情况下,使用链接列表是有意义的,即使它看起来应该是有效的 如果希望始终对集合进行排序,则确实应该使用有序集合,如TreeSet,甚至可以使用PriorityQueue。它将提供更干净的代码(以及更快的排序),因为您不必一直担心自己调用sort()。您可以使用排序列表上的Collections#binarySearch来找到正确的插入点。Array

我想维护一个大小为的有序
列表,在
LinkedList
上调用
sort()
会破坏性能,因为默认实现了
List.sort()
列表
转换为数组进行排序。在很少的情况下,使用
链接列表是有意义的,即使它看起来应该是有效的


如果希望始终对集合进行排序,则确实应该使用有序集合,如
TreeSet
,甚至可以使用
PriorityQueue
。它将提供更干净的代码(以及更快的排序),因为您不必一直担心自己调用
sort()

您可以使用排序列表上的
Collections#binarySearch
来找到正确的插入点。ArrayList可能会比LinkedList性能更好,尤其是对于较大的大小,但这很容易测试

我运行了一个各种方法的微型基准测试:在每次插入后使用sort或二进制搜索插入到正确的位置,使用ArrayList(AL)和LinkedList(LL)。我还添加了Commons树列表和番石榴树列表

结论

  • 在被测试的算法中,最好的算法是使用
    TreeMultiset
    ,但严格来说,它不是一个列表-下一个最好的选择是使用
    ArrayList
    +binarySearch
  • ArrayList在所有情况下的性能都优于LinkedList,LinkedList需要几分钟才能完成100000个元素(ArrayList只需不到1秒)
最佳执行者代码,供参考:

@Benchmark public ArrayList<Integer> binarySearchAL() {
  ArrayList<Integer> list = new ArrayList<> ();

  Random r = new Random();
  for (int i = 0; i < n; i++) {
    int num = r.nextInt();
    int index = Collections.binarySearch(list, num);
    if (index >= 0) list.add(index, num);
    else list.add(-index - 1, num);
    current = list.get(0); //O(1), to make sure the sort is not optimised away
  }
  return list;
}
对于10万件物品:

c.a.p.SO28164665.binarySearchAL    100000  avgt        6  890.585 ± 68.730  ms/op
c.a.p.SO28164665.treeMultiSet      100000  avgt        6  105.273 ±  9.309  ms/op

由于java没有内置multiset,这是适合您情况的完美数据结构,因此我建议使用guava库中的


多集允许重复元素,树多集还将增加保持集合排序的好处。

在Oracle Java/OpenJDK 7或更高版本下,两者的渐进性能相似
Collections.sort
将列表加载到一个数组中,对数组进行排序,然后通过迭代(使用
ListIterator
)将数组重新加载到列表中,替换其元素

在这两种情况下,这都是对大部分排序的数组的数组排序(在OpenJDK 7和更高版本中是
O(n)
,因为它使用了timsort),再加上两个列表迭代(在这两种情况下都是
O(n)
,尽管我希望
LinkedList
有一个更糟糕的常量)。因此,总体而言,这是一个
O(n)
过程,但对于
LinkedList
来说可能会更慢

如果您正在批量插入元素,那么批量插入将是整体
O(n^2)
,这比全部插入和排序要慢,或者按照
Smac89
的建议使用
TreeMultiset
(两者都是
O(n log(n))

为了好玩,这里有一个非常糟糕的方法,可以滥用
TreeSet
来允许它存储重复的元素:

public class AwfulComparator<E extends Comparable<E>> implements Comparator<E> {
    public int compare(E o1, E o2) {
        int compared = o1.compareTo(o2);
        return (compared == 0)?1:compared; // Never compare equal
    }
}

new TreeSet<String>(new AwfulComparator<>());
公共类AwfulComparator实现Comparator{
公共整数比较(EO1,EO2){
int比较=o1。与(o2)比较;
返回(比较==0)?1:比较;//从不比较相等
}
}
新树集(新的awfulcomarator());

<>代码> ,如果排序是您的主要性能考虑,您应该考虑使用被设计来维护订单的数据结构。 使用普通Java基类,您可以使用以下任何一种:

PriorityQueue (in case you want to retain duplicates)
TreeSet (filter duplicates)

在任何情况下,对所有版本进行原型化并运行一些基准测试+评测都是最简单的

你已经回答了你的问题,linkedlist显然更有效。另一种选择是像…@Smac89这样的二叉树,我的集合中有重复的元素,所以不能使用
集合
,但是类似于
二叉搜索树
的东西会很好,因为它比
集合的性能更好。sort()
@Smac89为什么您认为它显然更有效?@assylias Well OP确实说过…
,但由于我将经常调用sort()方法,我逐渐了解到linkedList在对列表进行排序时会执行得更好,并且将是比ArrayList更好的选择,因为它不会像ArrayList那样移动元素(使用数组作为基础数据结构)。
和ofc,因为对链表进行合并排序是O(nlogn)操作(如果完成)right@Smac89我得到的结果似乎与您的说法不一致。还要注意,在Java中对LinkedList进行排序要比对ArrayList进行排序慢,因为前者意味着将项目的额外副本添加到数组中。我希望列表中的元素重复,因此不能使用
Set
PriorityQueue
只是部分排序,因此这对我的情况也没有帮助。
Collections.sort()
将列表转换为数组,然后对其进行排序。因此,您可以有效地使用
O(nLogn)
complexity..这是你能得到的最好结果。@MeenaChaudhary那么
ArrayList
是你最明智的选择。
LinkedList
的性能非常差(几乎在任何情况下都是如此)。合并排序不需要随机访问,可以在
O(n log n)中处理链表 >与数组相同。这就是< C++ > />代码>:C++中的排序< <代码> >是“代码> LIKEDLIST。排序< /COD>不是一个专门的合并排序。在OpenJDK上,在执行<代码>集合时,在任何时候都没有。排序< < /代码>是<代码> GET()/Cux>方法。它只使用<代码> toRayAy())/>代码>和<代码> ListItRealTor()。
+1用于二进制搜索:)。但如果OP使用
数组列表,则插入后的移位需要时间。在这种情况下,
LinkedList
会更有效。我不知道,你可能是对的。binarySearch在LinkedList上的速度可能较慢,但插入速度更快…@LostMind刚刚运行了一些
PriorityQueue (in case you want to retain duplicates)
TreeSet (filter duplicates)