mergeSort与List接口

时间:2013-04-28 11:55:43

标签: java sorting

我写了下面的代码,但是我得到了堆栈溢出。合并方法在单独测试时可以正常工作。当我查看代码时,我有隧道视觉,我无法理解为什么它不起作用,所以有人可以指出错误给我。非常感谢!

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;
}

1 个答案:

答案 0 :(得分:1)

我认为你的mergeSort实现不能很好地扩展。您正在使用copy方法将输入列表的相应范围复制为对mergeSort的递归调用的输入。如果考虑递归的整个深度,则需要在每个级别上增加整个输入列表大小的空间。

这意味着您的代码需要log2(n)次n的内存,其中n是输入列表的大小。如果您要合并排序大小为65'536元素的列表,您的代码将创建它的副本,以便它将使用峰值量log2(65'536)=输入表的内存要求的16倍。这很可能导致StackOverflowException

要解决这个问题,我会重写mergeSort方法(或者更确切地说是创建它的重载版本)来接受列表以及指向列表的下限和上限。这样,您就不需要在每个递归步骤上复制列表。另一方面,只要下边界和上边界分隔的范围只包含一个元素,就会返回一个新的List,其中只包含merge()将运行的单个元素。这样,您只复制整个输入列表一次(即在最低递归级别),并且最终只使用输入列表占用的内存的两倍(复杂性方面为O(n))。只要merge()将通过这些单元素列表并且将创建一个新的中间结果列表,单元素列表将可用于GC。