【问题标题】:Why is compareTo method so slow when sorting an array of objects为什么在对对象数组进行排序时 compareTo 方法这么慢
【发布时间】:2014-04-29 08:25:43
【问题描述】:

我有一个 Entry 对象数组(它是创建基本电话目录的解决方案的一部分) - 每个 Entry 对象包含三个字段(这是电话目录的数据) public String surname; public String initial; public String number;

最初,当将这些添加到数组时(我知道数组不是电话目录之类的数据结构的好选择,但它在规范中),在添加每个条目后,它被排序 -想法是,由于 java 库排序使用混合 Timsort 来查找已排序数据的运行,它几乎与将条目插入到正确位置和直接将新条目插入到正确的位置。

排序方法运行如下

protected void sort() {

    /*
     * Uses comparator because else it fails to sort the null values to the end of the array, and
     * throws null pointer exception instead
     */

    Arrays.sort(this.directory, new Comparator<Entry>() {
        public int compare(Entry entry1, Entry entry2) {
            if (entry1 == null) { // if entries are null will sort to back of
                                // array
                return 1;
            }

            if (entry2 == null) {
                return -1;
            }

            return entry1.surname.compareTo(entry2.surname); //NB this line
        }

    });
}

但是,有人向我指出,直接与另一个对象的字段交互是不好的风格(这是有道理的!)。所以上面标记的行被替换为 return entry1.surname.compareTo(entry2.surname);

这意味着它使用入口类的 compareTo 方法。但是-出于某种我不明白的原因-这大大减慢了速度。它从能够在一秒钟内添加 3000 个条目到花费超过 30 秒 - 考虑到下面的 compareTo 方法,为什么需要这么长时间?

    @Override
public int compareTo(Entry o) {

    if (this.getClass() == null) {
        return -1;
    }

    if (o == null) {
        return 1;
    }

    if (this.surname.equalsIgnoreCase(o.surname)) {
        return this.initial.compareToIgnoreCase(o.initial);
    }

    return this.surname.compareToIgnoreCase(o.surname);

}

【问题讨论】:

  • 您使用ignoreCase 方法之一,为什么要测试相等性?另外,null 元素?首先尝试避免这种情况
  • 如果两个参数都是null会发生什么?在这种情况下,它们应该相等。
  • 删除if (this.getClass() == null){...}。它总是错误的。
  • 另外,您将姓氏比较两次。致电this.surname.compareToIgnoreCase 并保存结果。如果为零,则它们相等。
  • @LouisWasserman 我不确定哪种方法也会阻止您的引用 - 如果它是比较器,那么如果它们都是空的,那么如果它们的排名相等或放置一个,实际上并没有任何区别在另一个之上。它不应该影响其他任何东西,因为比较器在排序方法完成后被丢弃。如果你在谈论 compareTo()..well..如果它们都是 null 那么它会在能够运行 compareTo 方法之前抛出 NullPointerException

标签: java arrays performance sorting


【解决方案1】:

您的平局解析逻辑是相反的:不是预先比较姓氏是否相等,而是先将它们与compareToIgnoreCase 比较,然后检查结果是否为零。否则,您实际上是在进行两次比较:

int res = this.surname.compareToIgnoreCase(o.surname);
return res != 0 ? res : this.initial.compareToIgnoreCase(o.initial);

假设平局数量很少,这应该会加快你的比较速度大约两倍。

此外,您的代码还有其他的低效之处:例如,对this.getClass() 的结果进行空检查是没有意义的,因为它永远不会是null

【讨论】:

    猜你喜欢
    • 2015-12-27
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 2017-03-21
    • 1970-01-01
    • 2016-08-09
    • 2019-12-29
    相关资源
    最近更新 更多