Java:ArrayList 的合并排序不起作用

Java: Mergesort for ArrayList does not work

它正确地比较了对象,但将包含重复对象的列表的大小加倍。

public static void mergeSort(List<Person> list) {
        List<Person> helper = new ArrayList<Person>(list.size());
        mergeSort(list, helper, 0, list.size());
    }

    private static void mergeSort(List<Person> list, List<Person> helper, int low, int high) {
        if(low < high) {
            int middle = (low+high)/2;
            mergeSort(list, helper, low, middle); //sort left half
            mergeSort(list, helper, middle+1, high); //sort right half
            merge(list, helper, low, middle, high); // merge
        }
    }

    private static void merge(List<Person> list, List<Person> helper, int low, int middle, int high) {
        for(int i=low; i<= high; i++) {
            helper.add(i, list.get(i));
        }

        int helperLeft = low;
        int helperRight = middle + 1;
        int current = low;

        /**
         * Iterate through helper array, copying back smaller element in the original list 
         */
        while(helperLeft <= middle && helperRight <= high) {
            if(helper.get(helperLeft).isLessThan( helper.get(helperRight))) {
                list.add(current, helper.get(helperLeft));
                helperLeft++;
            } else {
                list.add(current, helper.get(helperRight));
                helperRight++;
            }
            current++;
        }

        //Copy remaining elements
        int remaining = middle - helperLeft;
        for(int j=0; j <= remaining; j++) {
            list.add(current+j, helper.get(helperLeft+j));
        }

    }

Person.java

public class Person implements Comparable<Person>{

    private String personId;
    private String month;
    private String day;
    private String year;
    private Date personDay;
    static SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");

    public Person(String id, String month, String day, String year) {
        this.personId = id;
        this.month = month;
        this.day = day;
        this.year = year;
    }

    @Override
    public int compareTo(Person person) {
        return this.getPersonDay().compareTo(person.getPersonDay());
    }

    public boolean isLessThan(Person person) {
        boolean isLess = false;
         if(this.getPersonDay().compareTo(person.getPersonDay()) < 0) {
             isLess = true;
         }
         return isLess;
    }
}

测试对象

List<Person> list = new ArrayList<Person>();
        list.add(new Person("1L", "10", "1", "1960"));
        list.add(new Person("1L", "4", "5", "1978"));
        list.add(new Person("1L", "9", "17", "1986"));
        list.add(new Person("1L", "2", "15", "1971"));
        list.add(new Person("1L", "7", "1", "1971"));

有几个问题...

不要使用List#add,使用List#set

而不是...

    while(helperLeft <= middle && helperRight <= high) {
        if(helper.get(helperLeft).isLessThan( helper.get(helperRight))) {
            list.add(current, helper.get(helperLeft));
            helperLeft++;
        } else {
            list.add(current, helper.get(helperRight));
            helperRight++;
        }
        current++;
    }

    //Copy remaining elements
    int remaining = middle - helperLeft;
    for(int j=0; j <= remaining; j++) {
        list.add(current+j, helper.get(helperLeft+j));
    }

使用...

    while(helperLeft <= middle && helperRight <= high) {
        if (helper.get(helperLeft).isLessThan(helper.get(helperRight))) {
            list.set(current, helper.get(helperLeft));
            helperLeft++;
        } else {
            list.set(current, helper.get(helperRight));
            helperRight++;
        }
        current++;
    }

    //Copy remaining elements
    int remaining = middle - helperLeft;
    for (int j = 0; j <= remaining; j++) {
        list.set(current + j, helper.get(helperLeft + j));
    }

Lists,像数组一样,是零索引的,所以不是...

    for (int i = low; i <= high; i++) {
        helper.add(i, list.get(i));
    }

你应该使用

    for (int i = low; i < high; i++) {
        helper.add(i, list.get(i));
    }

而不是...

    while (helperLeft <= middle && helperRight <= high) {

你应该使用...

    while (helperLeft < middle && helperRight < high) {

因此,在对您的示例中缺少的代码进行更正以适应之后(例如 getPersonDay),我得到类似...

----Unsorted
1L; 10/01/1960
1L; 04/05/1978
1L; 09/17/1986
1L; 02/15/1971
1L; 07/01/1971

----Sorted
1L; 10/01/1960
1L; 02/15/1971
1L; 07/01/1971
1L; 04/05/1978
1L; 09/17/1986

当high-low<2时,忘记排序List.You这个小范围需要处理那个小case,如下

 private static void mergeSort(List<Person> list, List<Person> helper, int low, int high) {
    if(high - low<2) {
        sortTheSmallList(list,low,high);
    }else{
        int middle = (low+high)/2;
        mergeSort(list, helper , low, middle); //sort left half
        mergeSort(list, helper, middle+1, high); //sort right half
        merge(list, helper, low, middle, high);
    }
}