【问题标题】:Issue with merge sort Algorithm合并排序算法的问题
【发布时间】:2019-10-11 23:17:00
【问题描述】:

合并排序算法不起作用。继续获取IndexOutOFBoundsError。我相信问题可能是因为没有哨兵。当leftarrayrightarray 将自身复制到k 时,我需要创建一个循环,其中一个数组用完了数字,这会导致错误。我需要一些帮助来创建这个哨兵。

private static <T> void mergeSort(Comparable<? extends T>[] items, int begIndx, int endIndx) {
    if (items.length > 1) {
        int midIndx = items.length / 2;
        @SuppressWarnings("unchecked")
        T[] left = (T[]) new Object[midIndx];
        @SuppressWarnings("unchecked")
        T[] right = (T[]) new Object[items.length - midIndx];

        for (int i = 0; i < midIndx; i++) {
            left[i] = (T) items[i];
        }
        for (int i = midIndx; i < items.length; i++) {
            right[i] = (T) items[i];
        }

        mergeSort(items, begIndx, midIndx);
        mergeSort(items, midIndx + 1, endIndx);
        merge(items, begIndx, midIndx, endIndx);
    }
}

@SuppressWarnings("unchecked")
private static <T> void merge(Comparable<? extends T>[] array,
                              int begIndx, int midIndx, int endIndx) {
    int sizeOfLeft = midIndx - begIndx + 1;
    int sizeOfRight = endIndx - midIndx;

    /// change to generic later
    @SuppressWarnings("unchecked")
    T[] leftArr = (T[]) new Object[sizeOfLeft + 1];
    @SuppressWarnings("unchecked")
    T[] rightArr = (T[]) new Object[sizeOfRight + 1];

    for (int i = 0; i < sizeOfLeft; i++) {
        leftArr[i] = (T) array[begIndx + i];
    }
    for (int j = 0; j < sizeOfRight; j++) {
        rightArr[j] = (T) array[midIndx + j + 1];
    }

    int i = 0;
    int j = 0;

    // changed to less than or equal to rather than "less than"
    // this is because this is a zero based index system
    // and because endeIndex is not a length but an index,
    // you need to populate it.
    for (int k = begIndx; k <= endIndx; k++) {
        // use comparable here
        if (((Integer) leftArr[i]).compareTo((Integer) rightArr[j]) <= 0) {
            array[k] = (Comparable<? extends T>) leftArr[i];
            i = i + 1;
        } else if (((Integer) leftArr[i]).compareTo((Integer) rightArr[j]) >= 0) {
            /// just replaces it so don't use comparable
            array[k] = (Comparable<? extends T>) rightArr[j];
            j = j + 1;
        } else if ((Integer) leftArr[sizeOfLeft] == null) {
            array[k] =  (Comparable<? extends T>) rightArr[j];
            j = j + 1;
        } else if ((Integer) rightArr[sizeOfRight] == null) {
            array[k] = (Comparable<? extends T>) leftArr[i];
            i = i + 1;
        }
    }
}

我创建了一个整数数组arr = new Integer[5]。所以应该对这 5 个数字进行排序。

【问题讨论】:

  • 请定义“不工作”。你有错误吗?输出不正确?
  • 我收到 IndexoutOfbounds 错误。
  • 您的至少一个问题是-在第一种方法中-您访问范围为 [midRange, items.length] 的正确数组,而您的正确数组具有索引 [0, items.length - 中档]。
  • 您的正确数组循环定义错误。您正在尝试分配给索引 right[midIndx],而您应该分配给 right[i - midIndx],但不幸的是,这不是唯一的问题

标签: java sorting merge indexoutofboundsexception mergesort


【解决方案1】:

您的代码中存在多个问题:

  • 不清楚索引endIndx 是包含还是排除。如果排除endIndx,代码会简单得多,并且对数组进行排序的初始调用很简单:mergesort(arr, 0, arr.length);

  • mergesort 中的初始测试不正确:您应该测试切片是否有超过 1 个元素,而不是测试数组长度:

    if (endIndx - begIndx > 1)
    
  • leftright 数组在 mergesort 中未使用。

  • 不需要在merge 中的数组leftright 中分配一个额外的元素,将数组索引值与子数组的长度进行比较要简单得多。这种sentinel 方法令人困惑,不应使用。

这是一个简化版:

private static <T> void mergeSort(Comparable<? extends T>[] items, int begIndx, int endIndx) {
    if (endIndx - begIndx > 1) {
        int midIndx = items.length / 2;
        mergeSort(items, begIndx, midIndx);
        mergeSort(items, midIndx, endIndx);
        merge(items, begIndx, midIndx, endIndx);
    }
}

@SuppressWarnings("unchecked")
private static <T> void merge(Comparable<? extends T>[] array,
                              int begIndx, int midIndx, int endIndx) {
    int sizeOfLeft = midIndx - begIndx;
    int sizeOfRight = endIndx - midIndx;

    /// change to generic later
    @SuppressWarnings("unchecked")
    T[] leftArr = (T[]) new Object[sizeOfLeft];
    @SuppressWarnings("unchecked")
    T[] rightArr = (T[]) new Object[sizeOfRight];

    for (int i = 0; i < sizeOfLeft; i++) {
        leftArr[i] = (T)array[begIndx + i];
    }
    for (int j = 0; j < sizeOfRight; j++) {
        rightArr[j] = (T)array[midIndx + j];
    }

    int i = 0;
    int j = 0;
    int k = begIndx;

    while (i < sizeOfLeft && j < sizeOfRight) {
        /// use comparable to compare actual values
        if ((Integer)leftArr[i]).compareTo((Integer)rightArr[j]) <= 0) {
            array[k] = (Comparable<? extends T>)leftArr[i];
            i++;
            k++;
        } else {
            array[k] = (Comparable<? extends T>)rightArr[j];
            j++;
            k++;
        }
    }
    while (i < sizeOfLeft) {
        array[k] = (Comparable<? extends T>)leftArr[i];
        i++;
        k++;
    }
    while (j < sizeOfRight) {
        array[k] = (Comparable<? extends T>)rightArr[j];
        j++;
        k++;
    }
}

【讨论】:

    猜你喜欢
    • 2012-04-04
    • 2021-01-25
    • 2013-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    相关资源
    最近更新 更多