所以我现在正在学习MergeSort以解决Project Euler上的问题。
我正在尝试按字母顺序对列表中的5163个名称进行排序。我做了一些研究,发现MergeSort是一种相当有效的方法。
所以我编写了一个基于此link的实现。
以下是我的mergeSort
和merge
方法。
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);
那么我的名单怎么可能有一个零的大小?
答案 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)
您必须检查列表是否为空。