MergeSort IllegalArgumentException

时间:2016-10-10 05:29:39

标签: java algorithm sorting mergesort

所以我现在正在学习MergeSort以解决Project Euler上的问题。

我正在尝试按字母顺序对列表中的5163个名称进行排序。我做了一些研究,发现MergeSort是一种相当有效的方法。

所以我编写了一个基于此link的实现。

以下是我的mergeSortmerge方法。

public static List<String> mergeSort(List<String> list){

    if (list.size() == 1){ //if fully divided
        return list;
    }

    List<String> leftSide = list.subList(0, list.size()/2);
    List<String> rightSide = list.subList(list.size()/2 + 1, list.size());

    leftSide = mergeSort(leftSide);
    rightSide = mergeSort(rightSide);

    return merge(leftSide, rightSide);

}

public static List<String> merge(List<String> listA, List<String> listB){

    List<String> listC = new LinkedList<String>();

    while (!listA.isEmpty() & !listB.isEmpty()){ //while both have elements
        if (listA.get(0).compareTo(listB.get(0)) > 1){ //if stringA is greater than stringB 
            listC.add(listA.get(0));
            listA.remove(0);
        } else { //if stringB is greater than stringA
            listC.add(listB.get(0));
            listB.remove(0);
        }
    }

    while (!listA.isEmpty()){ //while listA has elements 
        listC.add(listA.get(0));
        listA.remove(0);
    }

    while (!listB.isEmpty()){ //while listB has elements
        listC.add(listB.get(0));
        listB.remove(0);
    }

    return listC;

}

问题是,当我尝试将mergeSort方法用于我的名字列表时,它会给我以下错误:

  

线程“main”中的异常java.lang.IllegalArgumentException:fromIndex(1)&gt; toIndex(0)

指向这一行:

List<String> rightSide = list.subList(list.size()/2 + 1, list.size());

我真的不明白为什么会这样。在我看来,我使用了与教程中显示的完全相同的方法。

另外,根据我的理解,这个错误告诉我列表的大小为零。这将是list.size()/2 + 1可以等于1且list.size()可以等于零的唯一方式。但是,我不明白为什么我的列表可能为零。因为它将被分割直到大小为1,然后它将被返回。

我能看到它等于零的唯一方法是,如果它开始为零,但我已经确认我的list.size()是5163开始。

有人能帮助我指出我做错了什么吗?我确信这是非常简单的事情,但由于我刚开始学习这个,我不确定它是什么。

编辑:

我在这里查看列表的大小:

System.out.println(namesArray.size()); //prints "5163"
namesArray = mergeSort(namesArray);

那么我的名单怎么可能有一个零的大小?

2 个答案:

答案 0 :(得分:2)

  

我能看到它等于零的唯一方法是,如果它开始为零,但我已经确认我的list.size()是5163开始。

还有第二种方式。考虑在进入mergeSort输入子列表包含两个元素时,在递归过程中会发生什么。

List<String> leftSide = list.subList(0, list.size()/2);

以上变为list.sublist(0,1)。由于结束索引是独占,因此子列表包含一个元素。然后:

List<String> rightSide = list.subList(list.size()/2 + 1, list.size());

这变为list.sublist(2,2)。同样,由于结束索引是独占,因此会创建长度为零的 列表,或者一个emtpy列表 。现在当你到达递归调用

leftSide = mergeSort(leftSide);
rightSide = mergeSort(rightSide);

左侧递归有效,但右侧递归传递零长度列表。在mergeSort的顶部,您有

if (list.size() == 1){ //if fully divided
    return list;
}

检查列表大小1的终止条件,但不会阻止代码尝试处理空的零长度列表。这就是在此之后立即引起异常的原因。

如果您将测试更改为if (list.size() <= 1),那么您已经阻止了异常,但仍会出现问题,因为由于结束索引问题,某些元素不会被排序。

正确的解决方案是更改一行:

List<String> rightSide = list.subList(list.size()/2 + 1, list.size());
                                                    ^^^
        Remove this----------------------------------^

答案 1 :(得分:0)

如果您有空列表,请致电

List<String> rightSide = list.subList(0/2 + 1, 0);

所以你的索引比toIndex大。这引起了例外。

形成javadoc

  

返回指定fromIndex(包含)和toIndex(独占)之间此列表部分的视图。 (如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表由此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然。返回的列表支持此列表支持的所有可选列表操作。    此方法消除了对显式范围操作(对于数组通常存在的排序)的需要。任何需要列表的操作都可以通过传递subList视图而不是整个列表来用作范围操作。例如,以下习语从列表中删除了一系列元素:             list.subList(from,to).clear();

     

可以为indexOf和lastIndexOf构造类似的习语,Collections类中的所有算法都可以应用于subList。       如果支持列表(即,此列表)在结构上以除了返回列表之外的任何方式进行修改,则此方法返回的列表的语义将变为未定义。 (结构修改是那些改变了这个列表的大小,或以其他方式扰乱它的方式,正在进行的迭代可能会产生不正确的结果。)

     

参数:fromIndex - subList的低端点(含)

     

toIndex - subListReturns的高端点(不包括):此列表中指定范围的视图

     

抛出:IndexOutOfBoundsException - 表示非法端点索引值(fromIndex&lt; 0 || toIndex&gt; size || fromIndex&gt; toIndex)

您必须检查列表是否为空。