更高效的排序算法?

时间:2015-02-06 15:29:17

标签: java algorithm sorting

我正在寻找一种比Arrays.sort()更好的算法。 我知道这看起来像是一个万次问的愚蠢问题,但请继续阅读。

让我们有两个实现Comparable的类,其自然顺序基于int值。第一个compareTo方法如下所示:

 public int compareTo(ComparableInteger o) {
     return this.value - o.value;        
 }

第二个是:

public int compareTo(ComparableInteger o) {
    if (this.value > o.value) {
        return 1;
    } else {
        if (this.value == o.value) {
            return 0;
        } else {
            return -1;
        }
    }
}

当我在这些条款的实例列表上调用Collections.sort时,它们的表现大致相同。

我的问题是,是否存在排序算法,这会使第一个compareTo方法的附加信息受益。 在第一个示例中,添加的信息是:

我们有三个值ComparableInteger

a == 1
b == 2
c == 3

现在,当我们将ca进行比较时,得到2,当我们将cb进行比较时,我们得到1.从compareTo实施它很明显,b应该在a之后,因为c.compareTo(a) > c.compareTo(b)所以我们知道正确的顺序。现有的Comparable合同不需要这个,需要进行另一次比较。例如,以下实现也满足(至少我希望)合同,但给出不同的结果(数字排序,但偶数数字在奇数之前)

public int compareTo(ComparableInteger o) {
    if (value % 2 == o.value % 2){
        return value - o.value;
    } else {
        if (value % 2 == 1){
            return 1;
        }else{
            return -1;
        }
    }
}
  • 我很清楚第一个例子不是声音,因为int可能会溢出

5 个答案:

答案 0 :(得分:3)

排序算法的效率有很多可以依赖的东西,但有一点需要注意的是,一般来说,如果你基于元素之间的比较进行排序,那么最快的渐近运行时就是{{1} }。

然而,可以构建一种场景,其中排序可以比Ω(n lg n)更快地完成,但这需要使用更多信息而不仅仅是比较。这些是所谓的“线性排序”,它使用元素的进行排序,而不是与另一个元素进行比较。这些示例包括Bucket Sort,Counting Sort和Radix Sort。

您提供的第一个比较方法确实提供了额外的信息,这可能会提高分拣速度,但仅限于受限条件。例如,如果您知道没有重复值,并且最小值和最大值之间的每个值仅使用一次,然后你可以通过以下方式进行排序:

  1. 执行线性搜索以找到最小值。
  2. 将每个元素与最小元素进行比较并放置在比较方法给出的指数处。
  3. 此方法应该花费n lg n时间。当然,除非对象包含除整数值之外的额外信息,否则您可以直接构造范围2n = O(n)。此外,如果您可以读取元素的整数值,则可以实现普通存储桶或对其进行计数排序。

    tl; dr :最快的基于比较的排序为min..max。当您可以读取元素的确切值时,可以更快地排序,但线性排序仅适用于某些受限情况。通常,您应该使用编程语言的内置类型。

答案 1 :(得分:2)

小心第一个比较,它并不完全一致。

 public int compareTo(ComparableInteger o) {
     return this.value - o.value; //not always correct
 }

作为Eric Lippert points out(本文适用于C#,但仍然适用于Java),首先比较是不安全的:

  

特别是对于输入Int32.MinValue和Int32.MaxValue,   差异是1.显然,最小可能的整数小于   最大可能的整数,但这种方法恰恰相反   导致!

正如您所提到的,其他溢出/下溢问题也会出现。

事实上,在比较之外,任何排序算法尝试使用" extra"信息。 "额外"信息是以一些额外的头痛和角落案件为代价的。

答案 2 :(得分:1)

我认为第一个compareTo中的额外信息与您的想法一样有用:在您的示例中,您只是通过结果之间的比较来替换对象之间的比较 of compareTo,无论排序算法如何,都是如此。

答案 3 :(得分:1)

  • 普通算法:3次比较

  • 您的算法:2次比较+之前差异的“缓存”值的1次比较。 (在您的示例中,检查2> 1将确定ab的顺序)

至于O的复杂性,它们是相同的,但我的感觉是你的实现在实践中会慢一些(并且更难以实现)。

答案 4 :(得分:0)

始终坚持核心Java Collection功能,例如Arrays.sort(),因为它们已经针对目前为止在答案中提到的各种细微差别进行了测试,大多数程序员都不会想到,他们也因性能而调整。当下一版本的Java出现时,您不必重新测试自己的排序例程。