QuickSort方法中的java.lang.IllegalArgumentException方法

时间:2018-11-22 19:53:58

标签: java algorithm sorting quicksort

我正在遵循以下伪代码:

function quicksort(array)
    if length(array) > 1
        pivot := select any element of array
        left := first index of array
        right := last index of array
        while left ≤ right
            while array[left] < pivot
                left := left + 1
            while array[right] > pivot
                right := right - 1
            if left ≤ right
                swap array[left] with array[right]
                left := left + 1
                right := right - 1
        quicksort(array from first index to right)
        quicksort(array from left to last index)

但是当我尝试在Java中实现它时,我会插入代码:

import java.util.Arrays;

public class ALGQuickSort {

public static void main(String[] args) {
    int[] array = {6, 3, 4, 8, 9, 10, 1};
    quickSort(array);
    System.out.println(Arrays.toString(array));
}

public static void quickSort(int[] array) {
    int pivot = array[array.length - 1];
    if (array.length > 1) {
        int left = 0;
        int right = array.length - 1;
        while (left <= right) {
            while (array[left] < pivot) {
                left++;
            }
            while (array[right] > pivot) {
                right--;
            }
            if (left <= right) {
                swap(array[left], array[right]);
                right--;
                left++;
            }
            int[] array1 = Arrays.copyOfRange(array, 0, right);
            int[] array2 = Arrays.copyOfRange(array, left, array.length - 1);
            quickSort(array1);
            quickSort(array2);

        }
    }

}

public static void swap(int a, int b) {
    int aux = a;
    a = b;
    b = aux;
}

}

系统在屏幕上显示以下错误:

  

线程“ main”中的异常java.lang.IllegalArgumentException:5> 4     在java.util.Arrays.copyOfRange(Arrays.java:3591)在   alg.quicksort.ALGQuickSort.quickSort(ALGQuickSort.java:43)在   alg.quicksort.ALGQuickSort.quickSort(ALGQuickSort.java:44)在   alg.quicksort.ALGQuickSort.main(ALGQuickSort.java:21)   C:\ Users \ Alex \ AppData \ Local \ NetBeans \ Cache \ 8.2 \ executor-snippets \ run.xml:53:   Java返回:1

该错误在该行中:

int[] array2 = Arrays.copyOfRange(array, left, array.length - 1);

有人可以帮助我吗?

2 个答案:

答案 0 :(得分:1)

首先,两行

int[] array1 = Arrays.copyOfRange(array, 0, right);
int[] array2 = Arrays.copyOfRange(array, left, array.length - 1);

是错误的。 您不得复制阵列。由于在递归调用中对临时副本进行排序,这将阻止Quicksort算法起作用。排序后的子数组将被丢弃。

程序中的另一个错误引发了一个例外:Arrays.copyOfRange的第三个参数是独占的。即它不会将元素from复制到to而是将from复制到to - 1。但是您已经从上限减去了一个,在Quicksort中可能会出现其中一个子数组的尺寸为 0 。在这种情况下,要复制的范围变为负数。例外。

还有第三个错误:您交换了伪代码的前两行。这将在空数组上崩溃。


最后,您不能以这种方式实现Quicksort算法,如伪代码所示,因为Java (与C不同)不支持数组切片。

您需要以将算法分为两种方法的方式来修改算法:

  • 一种对数组切片进行递归排序的方法
    请注意,我用fromto替换了数组的开始和结束。

    public static void quickSort(int[] array, int from, int to) {
      if (array.length <= 1)
        return;
      int pivot = array[to];
      int left = from;
      int right = to;
      while (left <= right) {
        while (array[left] < pivot)
          left++;
        while (array[right] > pivot)
          right--;
        if (left <= right) {
          swap(array[left], array[right]);
          right--;
          left++;
        }
        quickSort(array, from, right);
        quickSort(array, left, to);
      }
    }
    
  • 还有第二种方法对整个数组进行排序,该方法针对整个数组调用上述方法。

    public static void quickSort(int[] array) {
      return quickSort(array, 0, array.length - 1);
    }
    

答案 1 :(得分:1)

对快速排序算法的改进/更正:

  1. 更正您的交换方法:您使用的交换方法将不起作用。
  2. 递归调用应该在for循环之外:您的伪代码是正确的,但在您的实现中并非如此。
  3. 将数据透视表放置在正确的位置,然后对现在(确保)不包含数据透视元素的子数组进行递归调用。在while循环之后,请确保right+1 == left(想一想,您就会明白为什么这是真的)。现在将数组[left]与pivot元素交换,并递归调用2个不同的子数组(pivot的左子数组为beginIndex..right,pivot的右子数组为left+1..endIndex,其中我认为您需要对array[beginIndex..endIndex])进行排序
  4. 避免复制:最好避免复制数组的一部分(相反,您可以传递startIndexendIndex来表示想要的子数组排序)
  5. 使用随机快速排序:如果您不总是选择最后一个元素作为枢轴,这也更好(您可以在开始排序之前选择任何随机元素,然后然后将其与数组的最后一个元素交换。使用此策略,您不必在现有代码中进行太多更改)选择 random element as pivot (随机元素作为枢轴点)会更好。有关更多详细信息,请参见this链接。
  6. 将交换方法设为私有:与算法无关,但最好将交换方法设为私有,因为您可能不打算从此类的外部调用它。

如果您打算将索引为index1和index2的数组元素互换,那么以下代码将起作用:

public static void swap(int[] array, int index1, int index2) {
    int aux = array[index1];
    array[index1] = array[index2];
    array[index2] = aux;
}

以下是具有上述所有建议更改的最终代码:

public static void main(String[] args) {
    int[] array = {6, 30, 7, 23, 4, 8, 9, 10, 1, 90};
    quickSort(array, 0, array.length - 1);
    System.out.println(Arrays.toString(array));
}

public static void quickSort(int[] array, int beginIndex, int endIndex) {
    // System.out.println("called quick sort on the following : " + beginIndex + " " + endIndex);
    int arrayLength = endIndex - beginIndex + 1;
    int pivot = array[endIndex];
    if (arrayLength > 1) {
        int left = beginIndex;
        int right = endIndex - 1;
        while (left <= right) {
            // System.out.println(left + " " + right);
            while (left <= endIndex && array[left] < pivot) {
                left++;
            }
            while (right >= beginIndex && array[right] > pivot) {
                right--;
            }
            if (left <= right) {
                swap(array, left, right);
                right--;
                left++;
            }

        }
        swap(array, left, endIndex); // this is crucial, and you missed it
        if (beginIndex < right) {
            quickSort(array, beginIndex, right);
        }
        if (left + 1 < endIndex) {
            quickSort(array, left + 1, endIndex);
        }
    }

}

private static void swap(int[] array, int index1, int index2) {
    int aux = array[index1];
    array[index1] = array[index2];
    array[index2] = aux;
}