【问题标题】:MergeSort IllegalArgumentExceptionMergeSort IllegalArgumentException
【发布时间】:2016-10-10 05:29:38
【问题描述】:

所以我现在正在学习 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) > toIndex(0)

哪个指向这条线:

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

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

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

我可以看到它等于零的唯一方法是它是否从零开始,但我已经确认我的list.size() 是从 5163 开始的。

有人可以帮我指出我做错了什么吗?我确信这很简单,但由于我刚刚开始学习这个,我不确定它是什么。

编辑:

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

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

那么我的列表怎么可能是零大小的呢?

【问题讨论】:

    标签: java algorithm sorting mergesort


    【解决方案1】:

    我能看到它等于零的唯一方法是它是否从零开始,但我已经确认我的 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)。同样,由于结束索引是排他的,这将创建一个长度为零的列表,或一个空列表。现在当你到达递归调用时

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

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

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

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

    如果您将测试更改为if (list.size() &lt;= 1),您会阻止异常,但仍然会遇到问题,因为由于结束索引问题,某些元素不会被排序。

    正确的解决方法是换一行:

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

    【讨论】:

    • 是的,这正是我刚才调试发现的。如果我是正确的,删除​​ +1 应该可以解决这个问题吗?
    • 是的。我还会检查零长度并抛出运行时异常。你不能保证这个方法的调用者总是做正确的事。
    【解决方案2】:

    如果你有一个空列表,你调用

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

    所以你的 from 索引比 toIndex 大。这引发了异常。

    形成javadoc

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

    可以为 indexOf 和 lastIndexOf 构造类似的习语,并且可以将 Collections 类中的所有算法应用于子列表。 如果后备列表(即此列表)以除通过返回列表之外的任何方式进行结构修改,则此方法返回的列表的语义变得未定义。 (结构性修改是改变这个列表的大小,或者以其他方式扰乱它,使得正在进行的迭代可能产生不正确的结果。)

    Parameters:fromIndex - 子列表的低端点(含)

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

    Throws:IndexOutOfBoundsException - 对于非法的端点索引值(fromIndex size || fromIndex > toIndex)

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

    【讨论】:

    • 类似于我刚刚对@Saurav 的回答发表的评论,我知道这告诉我我的 list.size() 为零,但鉴于我的列表,我不明白这怎么可能不是从零开始的。
    • @BenjaminLowry 使用调试器你就会发现
    • 一开始就不是零。由于索引错误,其中一个子列表(深入递归)的长度为零。
    猜你喜欢
    • 2018-02-07
    • 2014-05-19
    • 1970-01-01
    • 2019-03-25
    • 2017-05-17
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多