简体   繁体   English

为什么Collections.sort使用相同的参数调用Comparator两次?

[英]Why does Collections.sort call Comparator twice with the same arguments?

I'm running an example to understand the behavior of Comparator in Java. 我正在运行一个示例来了解Comparator在Java中的行为。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;


    class HDTV {
    private int size;
    private String brand;

    public HDTV(int size, String brand) {
        this.size = size;
        this.brand = brand;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }
}

class SizeComparator implements Comparator<HDTV> {
    @Override
    public int compare(HDTV tv1, HDTV tv2) {
        int tv1Size = tv1.getSize();
        int tv2Size = tv2.getSize();
 System.out.println("Comparing :: "+tv1.getBrand()+" AND : "+tv2.getBrand());
        if (tv1Size > tv2Size) {
            return 1;
        } else if (tv1Size < tv2Size) {
            return -1;
        } else {
            return 0;
        }
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        HDTV tv1 = new HDTV(55, "Samsung");
        HDTV tv2 = new HDTV(60, "Sony");
        HDTV tv3 = new HDTV(42, "Panasonic");

        ArrayList<HDTV> al = new ArrayList<HDTV>();
        al.add(tv1);
        al.add(tv2);
        al.add(tv3);

        Collections.sort(al, new SizeComparator());
        for (HDTV a : al) {
            System.out.println(a.getBrand());


        }
        }
    }

The output is 输出是

Comparing :: Sony AND :Samsung 比较:: Sony AND:Samsung
Comparing :: Panasonic AND : Sony 比较:: Panasonic AND:Sony
Comparing :: Panasonic AND : Sony 比较:: Panasonic AND:Sony
Comparing :: Panasonic AND : Samsung 比较:: Panasonic AND:Samsung
Panasonic 松下
Samsung 三星
Sony 索尼

Why is it comparing two Objects Panasonic and Sony 2 times consecutively?? 为什么连续2次比较PanasonicSony两个对象? I don't find it is required to do that. 我发现没有必要这样做。

If this is Java 7 or later, it's using TimSort. 如果这是Java 7或更高版本,则使用TimSort。 TimSort starts off by running through the input and detecting or gathering ascending runs of 32 or more elements (in this implementation). TimSort首先运行输入并检测或收集32个或更多元素的升序(在此实现中)。 See countRunAndMakeAscending in the source code. 请参阅源代码中的countRunAndMakeAscending

Runs longer than 32 are left in place for now. 目前,已有超过32次的运行。 Runs shorter than 32 are lengthened by doing a binary insertion sort of subsequent elements into the current run until it's at least 32 elements long. 通过对当前运行中的后续元素进行二进制插入排序来延长小于32的运行,直到它至少为32个元素长。 See binarySort in the source code. 请参阅源代码中的binarySort

(The merge sorting approach is done only after runs of >= 32 are gathered. Since your input has only 3 elements, the entire sort is done using the binary insertion sort, and no merging is done.) (合并排序方法仅在收集> = 32的运行后才完成。由于您的输入只有3个元素,因此整个排序是使用二进制插入排序完成的,并且不进行合并。)

What countRunAndMakeAscending has to do is to detect runs by comparing adjacent elements. countRunAndMakeAscending必须做的是通过比较相邻元素来检测运行。 First it compares Sony to Samsung and then Panasonic to Sony. 首先,它将索尼与三星,松下与索尼进行比较。 The result is a run of length 2, [Samsung, Sony]. 结果是长度为2,[三星,索尼]。

Next, binarySort lengthens this run by taking the next element, Panasonic, and inserting it into the right place. 接下来, binarySort通过使用下一个元素Panasonic,并将其插入正确的位置binarySort延长此运行时间。 A binary search is done to find that place. 进行二分查找以找到该位置。 The midpoint of the run of 2 is location 1, which is Sony, so it compares Panasonic to Sony. 2的运行中点是位置1,这是索尼,因此它将松下与索尼进行比较。 (This is the repeated comparison.) Panasonic is less than Sony, so next comparison is between Panasonic and Samsung, which determines the proper insertion point. (这是重复的比较。)松下比索尼少,所以下一个比较是在松下和三星之间,这决定了正确的插入点。 We now have a run of length 3. 我们现在有一个长度为3的运行。

Since the entire input is of length 3, the sort is finished after four comparisons. 由于整个输入的长度为3,因此在四次比较后完成排序。

The duplicate comparisons occur because countRunAndMakeAscending and binarySort are separate sort phases, and it just so happens that the last comparison of the first phase is the same as the first comparison of the second phase. 由于countRunAndMakeAscendingbinarySort是单独的排序阶段,因此发生重复比较,并且恰好第一阶段的最后一次比较与第二阶段的第一次比较相同。

Sorting algorithms are a complex topic. 排序算法是一个复杂的主题。 Consider this very simple (but inefficient) algorithm. 考虑这个非常简单(但效率低下)的算法。

Compare the first item to the second item. 将第一项与第二项进行比较。 Keep track of the higher item and compare it to the next item. 跟踪较高的项目并将其与下一项目进行比较。 Keeping track of the highest item until the get to the end of the list to find the highest item in the list. 跟踪最高项目,直到到达列表末尾以查找列表中的最高项目。 Place highest one in a new list, and remove it from the original list. 将最高的一个放在新列表中,然后将其从原始列表中删除。

Then repeat the previous steps until the original list is empty. 然后重复前面的步骤,直到原始列表为空。

Because you are going through the list multiple times, you could end up comparing an item its neighbor multiple times. 因为您要多次浏览列表,所以最终可能会多次将项目与其邻居进行比较。 Perhaps even consecutively on different passes. 甚至可能连续不同的传球。

It depends on sorting algorithm, on how many times it calls compare method. 它取决于排序算法,它调用比较方法的次数。 Once we call Collections.sort() method, it goes to the implementation of sorting used in Collections.sort(). 一旦我们调用Collections.sort()方法,它就会转到Collections.sort()中使用的排序实现。

Collections.sort() implementation uses merge sort. Collections.sort()实现使用合并排序。 According to the Javadoc, only primitive arrays are sorted using Quicksort. 根据Javadoc,只使用Quicksort对原始数组进行排序。 Object arrays are sorted with a Mergesort as well. 对象数组也使用Mergesort进行排序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM