【问题标题】:Why could merge sort compare two items twice? [duplicate]为什么合并排序可以两次比较两个项目? [复制]
【发布时间】:2020-04-14 13:21:10
【问题描述】:

我正在尝试使用 'Collections.sort' 对数组列表进行排序。

这是我写的代码..

ArrayList<Student> arl = new ArrayList<>();
    arl.add(new Student(1, "tom", 26));
    arl.add(new Student(2, "brown", 22));
    arl.add(new Student(3, "kate", 24));
    arl.add(new Student(4, "brad", 23));
    System.out.println(arl);
    for(Student v : arl) {
        System.out.println(v);
    }
    Collections.sort(arl, new Comparator<Student>(){
        int count = 1;

        public int compare(Student s1, Student s2) {
            System.out.println("**compare "+count++ +" time***");
            System.out.println("s1: "+s1.getName() + "(id: " + s1.getId()+")");
            System.out.println("s2: "+s2.getName() + "(id: " + s2.getId()+")");
            return s1.getName().compareTo(s2.getName());
        }
    });

我得到一个排序列表,但我很好奇的是为什么 Java 将学生 id 3 与学生 id 2 比较两次?我不习惯 Mergesort 的定义,但这是因为 Java 是通过称为 Mergesort 的算法进行排序的吗?

**compare 1 time***
s1: brown(id: 2)
s2: tom(id: 1)
**compare 2 time***
s1: kate(id: 3)
s2: brown(id: 2)
**compare 3 time***
s1: kate(id: 3)
s2: tom(id: 1)
**compare 4 time***
s1: kate(id: 3)
s2: brown(id: 2)
**compare 5 time***
s1: brad(id: 4)
s2: kate(id: 3)
**compare 6 time***
s1: brad(id: 4)
s2: brown(id: 2)

【问题讨论】:

  • @Jakub Balinski 谢谢!如果有人已经问过这类问题,我应该先检查一下……我可以再问你一个问题吗?在第一次比较中,为什么 s1.getName 的值是 'brown' 而不是 'tom'。它最终将学生 id 1 与学生 id 2 进行比较,但这对我来说没有意义......
  • 需要多少细节? O(n × log(n)) 的时间复杂度已经暗示可以有比元素更多的操作(比较)。对于任意输入,没有任何排序算法可以避免这种情况。

标签: java algorithm collections


【解决方案1】:

正如我之前所说,您提出的主要问题已经回答了here

你在评论中提出的问题

在第一次比较中,为什么 s1.getName 的值是 'brown' 而不是 'tom'。它最终将学生 ID 1 与学生 ID 2 进行比较,但这对我来说没有意义......

它与Collections.sort 的实现直接相关,您可以找到here (OpenJDK 8)。在第一个排序阶段,countRunAndMakeAscending 函数被调用,我们可以在其定义中找到以下行:

if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
   ...

这是第一次使用您传递的比较器,并且碰巧传递给其compare 方法的第一个参数是具有更高索引的元素 (a[runHi++]) - 这就是它被打印的原因首先。

在我上面粘贴的链接中,您可以阅读此方法的完整实现。 更多关于Collections.sort算法的更多信息已经在第一个链接中问题的答案中被告知,所以如果您需要进一步解释,请查看此内容。

【讨论】:

  • 非常感谢!你的回答真的帮助我理解了逻辑!
  • 我很高兴听到这个消息!我真的很感激赞成并标记为已接受 - 这就是我们在这里说“谢谢”的方式;)
猜你喜欢
  • 1970-01-01
  • 2011-12-15
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 1970-01-01
  • 2011-01-14
相关资源
最近更新 更多