[英]Java implementation of Merge sort not working
I am trying to implement this version of merge sort, as seen in Introduction to Algorithms by Cormen. 我正在尝试实现此版本的合并排序,如Cormen的算法介绍中所见。
public static void merge(int[] A, int p, int q, int r) {
int lengthOfLeftSubarray = q - p + 1;
int lengthOfRightSubarray = r - q;
int[] L = new int[lengthOfLeftSubarray + 1];
int[] R = new int[lengthOfRightSubarray + 1];
for(int i=0; i<lengthOfLeftSubarray; i++)
L[i] = A[p + i];
for(int i=0; i<lengthOfRightSubarray; i++)
R[i] = A[q + i];
L[lengthOfLeftSubarray] = -1;
R[lengthOfRightSubarray] = -1;
int i = 0, j = 0;
for(int k=p; k<r; k++) {
if(L[i] <= R[j]) {****
A[k] = L[i];
i++;
}
else {
A[k] = R[j];
j++;
}
}
}
public static void mergesort(int[] A, int p, int r) {
if(p < r){
int q = (p + r) / 2;
mergesort(A, p, q);
mergesort(A, q + 1, r);
merge(A, p, q, r);
}
}
public static void main(String[] args) {
int[] unsorted = {12, 16, 4, 2, 7, 6};
Sorting.mergesort(unsorted, 0, unsorted.length - 1);
System.out.println(Arrays.toString(unsorted));
}
There are two issues that I have: 我有两个问题:
merge
method, where the four stars are ( * *). 代码在merge
方法中引发ArrayOutOfBounds异常,其中四颗星为( * *)。 Any ideas as to why this is happening? 有什么想法为什么会这样? On a cursory glance (ie I did not fix the code and run it locally to confirm the test case works), it looks like there's two bugs: 粗略浏览一下(即我没有修复代码并在本地运行以确认测试用例是否有效),看起来好像有两个错误:
1) 1)
for(int i=0; i<lengthOfRightSubarray; i++)
R[i] = A[q + i];
The right subarray should start at q + 1
just like it did when you did the recursive call: 正确的子数组应该从q + 1
开始,就像您进行递归调用时一样:
mergesort(A, q + 1, r);
2) In the OP comments it looks like you sorted this out, but your choice of sentinel value doesn't work. 2)在OP注释中,看起来好像您已对它进行了整理,但是您选择的哨兵值无效。 The point of the sentinel value depends on the algorithm. 前哨值的点取决于算法。 In this case, the point of the sentinel value was that it was supposed to be larger than any element in the input array unsorted
. 在这种情况下,前哨值的意义在于它应该大于输入数组unsorted
中的任何元素。 In particular, when you do the merge
the entire point is that you have two sorted sub arrays and want to merge them into one bigger, and still sorted , array. 特别是,当您进行merge
时,最重要的一点是您拥有两个已排序的子数组,并希望将它们合并为一个更大且仍已排序的数组。 So quick example: 这么简单的例子:
---- At the beginning ----
LEFT: {4, 12 16, INFINITY}
^
RIGHT: {2, 6, 7, INFINITY}
^
MERGED ARRAY: { }
^
---- After one iteration of the for loop ----
LEFT: {4, 12 16, INFINITY}
^
RIGHT: {2, 6, 7, INFINITY}
^
MERGED ARRAY: {2}
^
---- After second iteration of the for loop ----
LEFT: {4, 12 16, INFINITY}
^
RIGHT: {2, 6, 7, INFINITY}
^
MERGED ARRAY: {2, 4}
^
---- After third iteration of the for loop ----
LEFT: {4, 12 16, INFINITY}
^
RIGHT: {2, 6, 7, INFINITY}
^
MERGED ARRAY: {2, 4, 6}
^
---- After fourth iteration of the for loop ----
LEFT: {4, 12 16, INFINITY}
^
RIGHT: {2, 6, 7, INFINITY}
^
MERGED ARRAY: {2, 4, 6, 7}
^
And you can see why the sentinel value is important here. 您会在这里看到为什么哨兵价值很重要。 Since the right index is pointing at INFINITY
, the elements in the left sub array will be merged appropriately. 由于右索引指向INFINITY
,因此左子数组中的元素将被适当地合并。 It is easy to put -1
in place of INFINITY
and watch your merge
trigger an ArrayOutOfBounds
exception. 很容易将-1
替换为INFINITY
并看着您的merge
触发ArrayOutOfBounds
异常。
The entire reason the sentinel value is useful just because we don't want to handle the case when one sub array runs out of values. 哨兵值之所以有用的整个原因仅仅是因为我们不想处理一个子数组的值用完的情况。 You could easily implement the algorithm and check when aa sub array runs out of elements (at which point you'd just fill it in with the rest of the other sub array), but it's slightly less clean and harder to reason about. 您可以轻松实现该算法并检查一个子数组何时元素用完(此时,您只需将其填充到其他子数组的其余部分中即可),但它的简洁性较差,难以推理。 Putting a sentinel value ensures that neither sub array will run out of elements which allows you to write the proof (the the algorithm works!) in a simpler way. 放置哨兵值可确保两个子数组都不会用完元素,这使您可以以更简单的方式编写证明(算法起作用!)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.