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

余生颓废 提交于 2020-05-11 09:07:36

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!