如何使用Java接口比较器进行通用合并排序?

时间:2019-03-24 08:55:39

标签: java algorithm arraylist mergesort

我正在尝试合并排序列表,但出现ArrayOutOfBoundsError且无法修复它。

这是使用Comparator接口的通用列表的。现在,我正在使用Integer进行测试。

这是我的合并排序类:

public class ListMS<T> {
    private List<T> wholeList;
    private Comparator<T> comparator;

    public ListMS(List<T> list, Comparator<T> C){
        wholeList=new ArrayList<>();
        wholeList.addAll(list);
        comparator=C;
        mergeSort(wholeList, comparator);

    }

    public static <T> void merge(List<T> L1, List<T> L2,List<T> L, Comparator<T> C){
        int i=0;
        int j=0;
        while(i+j<L.size()){
            if(j==L2.size() || (i<L.size() && C.compare(L1.get(i),L2.get(j))<0)){
                L.set(i+j,L1.get(i++));
            }
            else{
                L.set(i+j,L2.get(j++));
            }
        }
    }

    public static <T> void mergeSort(List<T> L, Comparator<T> C){
        int size=L.size();
        if(size<2){
            return;
        }
        int half=size/2;
        List<T> L1=L.subList(0,half);
        List<T> L2=L.subList(half,size);

        mergeSort(L1,C);
        mergeSort(L1,C);

        merge(L1,L2,L,C);
    }

    public List<T> getWholeList(){
        return wholeList;
    }
}

我正在测试的东西:

public static void main(String[] args) {

        Comparator<Integer> C=new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        };

        List<Integer> list1K=generateList(1000);
        ListMS<Integer> list1KMerged=new ListMS<>(list1K, C);

        printList(list1K);
        printList(list1KMerged.getWholeList());


    }


    public static List<Integer> generateList(int size){
        List<Integer> listNumber=new ArrayList<>();
        for(int i=0;i<size;i++){
            int min=0;
            int max=size-1;
            int num=(int)(Math.random() * ((max - min) + 1)) + min;
            listNumber.add(num);
        }
        return listNumber;
    }

    public static void printList(List<Integer> L){
        for(int i=0;i<L.size();i++){
            System.out.print(L.get(i));
        }
    }

但是我得到多个ArrayOutOfBounds:

  

线程“主”中的异常java.lang.IndexOutOfBoundsException:索引:   1,尺寸:1 at   java.util.ArrayList $ SubList.rangeCheck(ArrayList.java:1225)在   java.util.ArrayList $ SubList.get(ArrayList.java:1042)在   ListMS.mergeSort(ListMS.java:40)处的ListMS.merge(ListMS.java:19)   ListMS.mergeSort(ListMS.java:37)上的ListMS.mergeSort(ListMS.java:37)     在ListMS.mergeSort(ListMS.java:37)在   ListMS.mergeSort(ListMS.java:37)上的ListMS.mergeSort(ListMS.java:37)     在ListMS.mergeSort(ListMS.java:37)在   ListMS.mergeSort(ListMS.java:37)上的ListMS.mergeSort(ListMS.java:37)     在ListMS。(ListMS.java:11)​​在   TestListMS.main(TestListMS.java:16)

1 个答案:

答案 0 :(得分:1)

基本上,这一行的merge()方法中的循环计数器有错误:

if(j == L2.size() || (i < L.size() && C.compare(L1.get(i), L2.get(j)) < 0))

如此修改合并功能,它将起作用:

public static <T> void merge(List<T> L1, List<T> L2,List<T> L, Comparator<T> C){
        int i=0;
        int j=0;
        int k=0;
        while(i < L1.size() && j < L2.size()) {
            if(C.compare(L1.get(i), L2.get(j)) < 0) {
                L.set(k++, L1.get(i++));
            }else {
                L.set(k++, L2.get(j++));
            }   
        }
        while(i < L1.size()) {
            L.set(k++, L1.get(i++));
        }
        while(j < L2.size()) {
            L.set(k++, L2.get(j++));
        }
    }

更新:

mergeSort函数中也存在多个错误。如此更改:

public static <T> void mergeSort(List<T> L, Comparator<T> C){
    int size=L.size();
    if(size<2){
        return;
    }
    int half=size/2;
    List<T> L1=new ArrayList<T>(L.subList(0,half));
    List<T> L2=new ArrayList<T>(L.subList(half,size));

    mergeSort(L1,C);
    mergeSort(L2,C);

    merge(L1,L2,L,C);
    printList(L);
}

L1和L2在旧代码中不是新的数组列表。它们只是指向与列表L中相同的内存位置的两个指针。因此,在合并功能中修改L也会修改L1和L2。为了解决这个问题,您需要创建两个具有单独内存分配的新子数组。

您还两次调用mergeSort(L1,C);,而不是分别在L1和L2上调用它。