我写了下面的代码,但是我得到了堆栈溢出。合并方法在单独测试时可以正常工作。当我查看代码时,我有隧道视觉,我无法理解为什么它不起作用,所以有人可以指出错误给我。非常感谢!
public static List<Comparable> mergeSort(List <Comparable> target){
if(target.size() < 2)
return target;
return merge(mergeSort(copy(0,(target.size()-1)/2 + 1,target)),mergeSort(copy((target.size()-1)/2 + 1,target.size(),target)));
}
private static List<Comparable> merge(List<Comparable> target1,List<Comparable> target2){
List <Comparable> result = new ArrayList <Comparable>();
while(target1.size() > 0 || target2.size() > 0){
if(target1.isEmpty())
result.add(target2.remove(0));
else if(target2.isEmpty())
result.add(target1.remove(0));
else if(target1.get(0).compareTo(target2.get(0)) < 0)
result.add(target1.remove(0));
else
result.add(target2.remove(0));
}
return result;
}
private static List<Comparable> copy(int startIndex, int endIndex, List<Comparable> target){
List <Comparable> result = new ArrayList <Comparable>();
for(int i = startIndex; i < endIndex; i++)
result.add(target.get(i));
return result;
}
答案 0 :(得分:1)
我认为你的mergeSort实现不能很好地扩展。您正在使用copy
方法将输入列表的相应范围复制为对mergeSort
的递归调用的输入。如果考虑递归的整个深度,则需要在每个级别上增加整个输入列表大小的空间。
这意味着您的代码需要log2(n)次n的内存,其中n是输入列表的大小。如果您要合并排序大小为65'536元素的列表,您的代码将创建它的副本,以便它将使用峰值量log2(65'536)=输入表的内存要求的16倍。这很可能导致StackOverflowException
。
要解决这个问题,我会重写mergeSort
方法(或者更确切地说是创建它的重载版本)来接受列表以及指向列表的下限和上限。这样,您就不需要在每个递归步骤上复制列表。另一方面,只要下边界和上边界分隔的范围只包含一个元素,就会返回一个新的List
,其中只包含merge()
将运行的单个元素。这样,您只复制整个输入列表一次(即在最低递归级别),并且最终只使用输入列表占用的内存的两倍(复杂性方面为O(n)
)。只要merge()
将通过这些单元素列表并且将创建一个新的中间结果列表,单元素列表将可用于GC。