问题
I'm running an example to understand the behavior of Comparator in 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
Comparing :: Panasonic AND : Sony
Comparing :: Panasonic AND : Sony
Comparing :: Panasonic AND : Samsung
Panasonic
Samsung
Sony
Why is it comparing two Objects Panasonic
and Sony
2 times consecutively??
I don't find it is required to do that.
回答1:
If this is Java 7 or later, it's using TimSort. TimSort starts off by running through the input and detecting or gathering ascending runs of 32 or more elements (in this implementation). See countRunAndMakeAscending in the source code.
Runs longer than 32 are left in place for now. 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. See binarySort in the source code.
(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.)
What countRunAndMakeAscending
has to do is to detect runs by comparing adjacent elements. First it compares Sony to Samsung and then Panasonic to Sony. The result is a run of length 2, [Samsung, Sony].
Next, binarySort
lengthens this run by taking the next element, Panasonic, and inserting it into the right place. 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. (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.
Since the entire input is of length 3, the sort is finished after four comparisons.
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.
回答2:
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() implementation uses merge sort. According to the Javadoc, only primitive arrays are sorted using Quicksort. Object arrays are sorted with a Mergesort as well.
回答3:
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.
来源:https://stackoverflow.com/questions/38136236/why-does-collections-sort-call-comparator-twice-with-the-same-arguments