【问题标题】:Java - Collections.sort() performanceJava - Collections.sort() 性能
【发布时间】:2011-02-22 10:51:35
【问题描述】:

我使用Collections.sort() 对一个LinkedList 进行排序,其元素实现了Comparable 接口,因此它们按自然顺序排序。在 javadoc 文档中,它说此方法使用 mergesort 算法,该算法具有 n*log(n) 性能。

我的问题是是否有更有效的算法来对我的 LinkedList 进行排序?

该列表的大小可能非常高,排序也非常频繁。

【问题讨论】:

  • 你是说内存还是cpu效率?
  • “非常高”是什么意思? 1000, 1000000, 100000000?
  • 因为正如许多人所指出的那样,O(n log n) 是基于比较的排序的可证明的下限,你真的不能做得更好。我认为人们可以为您提供更多帮助的唯一方法是,如果您提供有关您正在排序的内容或为什么需要对其进行排序的更多信息,以便我们可以根据您的具体情况推荐更好的解决方案。 =]
  • @iffy,你忘记了 bogosort:那是 O(1),不是吗?
  • 我相信该算法已被 JDK 7 中的双轴快速排序所取代。

标签: java algorithm collections sorting


【解决方案1】:

我正在试验大型数据集(GB 的数据)并实现了合并排序(@googlecode 有一个很好的例子)。但是,我正在使用 Collection.sort() 对我的临时缓冲区进行预排序,根据我的经验,Collection.sort() 在某个数据阈值处变得异常缓慢。使用 96MB 的辅助缓冲区,我可以在大约 30 秒内对其中一个缓冲区进行排序(注意:这在很大程度上取决于您使用的比较器 - 我使用带有非常复杂的列解析器的自定义列布局),但是将其增加到 128MB 块大小时间跳到超过 3 分钟。这与我可以观察到的较小块的线性(或接近线性)行为无关。这有很大的影响,在几乎所有情况下(?)使用较小缓冲区的合并排序都比使用 128MB 缓冲区的内存排序快。简而言之:合并排序是处理超过 100MB 边界的大型数据集的方法。我无法真正回答为什么会这样,而且这些数字甚至可能取决于机器(我的是 2.6GHz i7 和 16GB 内存上的 OS-X)。

【讨论】:

    【解决方案2】:

    就列表排序而言,不,所有基于一般数据的比较排序都是 O(N log(N))。

    如果您的重新排序是由于插入,那么您可以尝试批量插入,然后将排序与主列表合并 - 如果您有 B 个新项目,您可以在 O(B log(B)) 中对它们进行排序,然后执行两个列表的单级合并 O(N+B)。

    如果您的重新排序是由于项目值的更改,如果您将可变值更改为不可变值并将更改视为一批插入和删除,您可能能够进行类似的批处理。否则,您将无法避免对整个列表进行排序。

    如果您的要求允许,那么可以使用各种非链表结构,例如 TreeSet,它们可以更有效地维护排序顺序,但如果值是可变的,则会失败。

    【讨论】:

    • 如果再利用是由于插入,使用 TreeSet 会更有效:)
    • 这取决于他们是否需要重复的元素。
    • 即使这样他也可以使用 Google Collections 中的 TreeMultiset。
    【解决方案3】:

    如果您说列表将“非常频繁地”排序,则应考虑始终将列表保持在排序状态,例如使用树而不是 LinkedList也许你甚至可以使用SortedSet而不是List,如果你没有任何重复的值并且不需要任何列表操作(因为你一直在对它们进行排序)。检查SortedSet 实现的TreeSet 类。

    此实现为基本操作(添加、删除和包含)提供有保证的 log(n) 时间成本。

    如果你想迭代这个“列表”(实际上是一个集合),你可以使用类的迭代器。

    按升序返回此集合中元素的迭代器。

    如果列表中有重复值,则必须使用一些技巧(例如将值放入一个新类中,该类也有一些用于排序相等对象的增量)

    【讨论】:

      【解决方案4】:

      O(N log N) 渐近很好。也就是说,有线性时间O(N) 基于非比较的排序,例如计数排序和桶排序。这在以下情况下很有用,例如您正在对数百万个整数进行排序,但它们在 1..10 之间。

      此外,如果列表“几乎已排序”,则报告称在某些情况下,否则二次插入排序实际上会更好。

      这是否适用,甚至是否值得实施,取决于您的分析结果。我会说,除非它表明排序是瓶颈,否则不要担心。

      另见

      相关问题

      【讨论】:

        【解决方案5】:

        没有比n*log(n) 更好的通用排序算法。这是相当快的。一般来说,我的意思是您的数据没有特殊属性。

        【讨论】:

        • 它会将 LinkedList 转储到一个数组中,这可能需要一些时间。这不像在 ArrayList 中那样有效地实现。我想这就是问题所在。
        猜你喜欢
        • 1970-01-01
        • 2013-02-11
        • 1970-01-01
        • 2018-10-11
        • 2018-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-25
        相关资源
        最近更新 更多