【问题标题】:What sort does Java Collections.sort(nodes) use?Java Collections.sort(nodes) 使用什么类型?
【发布时间】:2010-10-19 16:31:57
【问题描述】:

我认为是 MergeSort,也就是 O(n log n)。

但是,以下输出不同意:

-1,0000000099000391,0000000099000427
1,0000000099000427,0000000099000346
5,0000000099000391,0000000099000346
1,0000000099000427,0000000099000345
5,0000000099000391,0000000099000345
1,0000000099000346,0000000099000345

我正在按序列号对 4 个节点的节点列表进行排序,排序正在进行 6 次比较。 我很困惑,因为 6 > (4 log(4))。谁能给我解释一下?

P.S. It is mergesort, but I still don't understand my results.

感谢大家的回答。谢谢汤姆纠正我的数学。

【问题讨论】:

  • (JDK7 中的Collections.sort 应该很少对部分排序的数据进行比较。Josh Bloch 移植了 Python 的 Tim 排序(合并排序的一个版本)。)
  • 如果是 log base 2 (notation??), 4 log[2] 4 = 4 log[2](2^2) = 4.2 log[2] 2 = 4.2.1 = 8 .(如果我没记错的话。)但是,是的,那里有一个常数。
  • 所以我猜JDK7默认使用timsort?

标签: java collections sorting time-complexity mergesort


【解决方案1】:

我写了一些您可能感兴趣的关于 Java 排序算法的内容,并采用了some performance measurements of Collections.sort()。目前的算法是带有插入排序的合并排序,一旦你达到一定大小的子列表(注意这个算法很可能会在 Java 7 中改变)。

您真的应该将大 O 表示法作为算法整体扩展方式的指示;对于特定的排序,精确的时间会偏离这个计算预测的时间(正如你将在我的图表上看到的那样,组合在一起的两种排序算法各自具有不同的性能特征,因此排序的总时间是有点复杂)。

也就是说,作为一个粗略的指导,每增加一倍的元素数量,如果将预期时间乘以 2.2,就不会太远了。 (不过,对于包含几个元素的非常小的列表,这样做并没有多大意义。)

【讨论】:

    【解决方案2】:

    处理数据量为 n 的算法 A(n) 在 O(f(n)) 中,对于某个函数 f,如果存在两个严格正的常数 C_inf 和 C_sup 使得:

    C_inf 。 f(n)

    需要注意的两点:

    • 实际的常量 C 可以是任何东西,并且 do 取决于操作的相对成本(取决于语言、VM、架构或您对操作的实际定义) .例如,在某些平台上,+ 和 * 具有相同的成本,而在另一些平台上,后者的成本要慢一个数量级。

    • “in O(f(n))”的数量是预期的操作计数,基于您正在处理的数据的一些可能任意模型。例如,如果您的数据几乎完全排序,则合并排序算法将主要是 O(n),而不是 O(n . Log(n))。

    【讨论】:

    • 对于任意大小的 n 位整数,+ 通常是 O(n) 和 * IIRC O(n log n)。您可以对算法做一些“有趣”的事情,只使用大整数和相对较少的(big-O)操作。
    • 快速排序是一个算法的典型例子,它主要是 O(n log n),但可以达到 O(n^2)(例如以第一个元素为轴的排序输入)。
    • 是的...对于所有这些复杂性估计任务,魔鬼在模型中。为了让它有任何用途,您通常还必须考虑最坏情况的复杂性,而不仅仅是预期成本。找到最坏的情况通常是个混蛋……
    【解决方案3】:

    你对四个节点进行了排序,所以你没有得到归并排序;排序切换到插入排序。

    在 Java 中,Arrays.sort() 方法使用归并排序或调整的快速排序,具体取决于数据类型和实现效率当排序的数组元素少于七个时切换到插入排序。 (维基百科,强调)

    Arrays.sort 被 Collections 类间接使用。

    最近接受的一个错误报告表明,Java 的 Sun 实现将在未来使用 Python 的 timsorthttp://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6804124

    (上面链接的 timsort 专着非常值得一读。)

    【讨论】:

    • 上周四还在 OpenJDK 论坛:核心库圆桌会议中提到。 mediacast.sun.com/users/robilad/media/… [MP3!]
    • 快速排序胜过合并排序。 Java 使用快速排序作为排序算法。
    • 快速排序上的常量真的很小,因为它就位。 Timsort,是归并排序和插入排序的混合体,在归并阶段使用插入排序,对此并没有太大的收获。与快速排序相比,该常数仍然很高。
    【解决方案4】:

    O(n log n) 并不意味着比较次数将等于或小于 n log n,只是所花费的时间将与 n log n 成比例缩放。尝试用 8 个节点,或 16 个节点,或 32 个节点进行测试,并检查时间。

    【讨论】:

    • 啊,我明白了。我假设这是比较次数。我的错。谢谢!
    • 这是一个相当少的比较,您可以轻松地将它们乘以 1000 以获得更好的结果。
    • 没错,但他的例子最初是 4 :)
    猜你喜欢
    • 1970-01-01
    • 2017-07-15
    • 2015-11-26
    • 2010-10-31
    • 1970-01-01
    • 2013-05-01
    • 2012-07-15
    • 1970-01-01
    相关资源
    最近更新 更多