英文:
What's wrong with my merge sort implementation?
问题
// 归并排序的合并操作
private static void merge(int[] a, int left, int middle, int right) {
int[] temp = new int[right - left + 1];
int leftCrawler = left, rightCrawler = middle;
int currentIndex = 0;
while (leftCrawler < middle && rightCrawler <= right) {
if (a[leftCrawler] < a[rightCrawler])
temp[currentIndex++] = a[leftCrawler++];
else
temp[currentIndex++] = a[rightCrawler++];
}
while (leftCrawler < middle)
temp[currentIndex++] = a[leftCrawler++];
while (rightCrawler <= right)
temp[currentIndex++] = a[rightCrawler++];
// 将 temp 复制回 a 数组
for (int i = 0; i < temp.length; i++)
a[left + i] = temp[i];
}
private static void mergeSort(int[] a, int left, int right) {
if (right > left) {
int middle = left + (right - left) / 2;
mergeSort(a, left, middle);
mergeSort(a, middle + 1, right);
merge(a, left, middle, right);
}
}
public static void mergeSort(int[] a) {
int left = 0, right = a.length - 1;
mergeSort(a, left, right);
}
所以,我认为问题可能出在我的合并操作上,然而我使用以下数组对其进行了测试:
int[] a = {2, 5, 7, 15, 8, 9, 10}
以及 left = 0,middle = 4 和 right = a.length - 1。
合并操作成功地完成了它所需做的工作。
我已经将我的归并排序实现与各种网站上的实现进行了比较,但我无法找出差异所在。
我的归并排序无法成功地对数组进行排序。我做错了什么?
英文:
// merge operation for merge sort
private static void merge(int[] a, int left, int middle, int right) {
int[] temp = new int[right - left + 1];
int leftCrawler = left, rightCrawler = middle;
int currentIndex = 0;
while (leftCrawler < middle && rightCrawler <= right) {
if (a[leftCrawler] < a[rightCrawler])
temp[currentIndex++] = a[leftCrawler++];
else
temp[currentIndex++] = a[rightCrawler++];
}
while (leftCrawler < middle)
temp[currentIndex++] = a[leftCrawler++];
while (rightCrawler <= right)
temp[currentIndex++] = a[rightCrawler++];
// copy temp into a
for (int i = 0; i < temp.length; i++)
a[i] = temp[i];
}
private static void mergeSort(int[] a, int left, int right) {
if (right > left) {
int middle = left + (right - left) / 2;
mergeSort(a, left, middle);
mergeSort(a, middle + 1, right);
merge(a, left, middle, right);
}
}
public static void mergeSort(int[] a) {
int left = 0, right = a.length - 1;
mergeSort(a, left, right);
}
So, I thought that the issue might be with my merge operation, however I tested it on the following array int[] a = {2, 5, 7, 15, 8, 9, 10}
with left = 0
, middle = 4
and right = a.length - 1
and the merge operation does what it needs to successfully.
I have compared my implementation of mergeSort to those on various websites and I can't spot a difference. My mergeSort will not successfully sort the array. What am I doing wrong?
答案1
得分: 1
问题可能出在你的复制代码上:
// 将 temp 复制到 a
for(int i = 0; i < temp.length; i++)
a[i] = temp[i];
你可能想要的是(注意 left + i
):
// 将 temp 复制到 a
for(int i = 0; i < temp.length; i++)
a[left + i] = temp[i];
(你的测试未检测出这个问题,因为 left
是 0。)
英文:
The problem might be with your copy:
// copy temp into a
for(int i = 0; i < temp.length; i++)
a[i] = temp[i];
What you probably want is (notice the left + i
):
// copy temp into a
for(int i = 0; i < temp.length; i++)
a[left + i] = temp[i];
(Your test did not detect the issue, since left
was 0.)
答案2
得分: 1
在你的代码中有 3 处错误:
-
合并循环未包括位于
a[middle]
的元素,因为你使用了leftCrawler < middle
,而应改为:while (leftCrawler <= middle && rightCrawler <= right)
-
第二个循环
while (leftCrawler < middle)
也必须改为:while (leftCrawler <= middle)
-
从
temp
复制回a
的循环在a
中使用了错误的索引。应为:// 将 temp 复制回 a for (int i = 0; i < temp.length; i++) a[left + i] = temp[i];
注意,第一个错误源于此处使用了有害的惯例,其中 right
和 middle
包含在切片中,而不是排除在外。排除右边界可以使代码更简单,无需任何容易出错的 +1
/-1
调整。
这是修改后的版本:
// 用于归并排序的合并操作
private static void merge(int[] a, int left, int middle, int right) {
int[] temp = new int[right - left];
int leftCrawler = left, rightCrawler = middle;
int currentIndex = 0;
while (leftCrawler <= middle && rightCrawler < right) {
if (a[leftCrawler] < a[rightCrawler])
temp[currentIndex++] = a[leftCrawler++];
else
temp[currentIndex++] = a[rightCrawler++];
}
while (leftCrawler <= middle)
temp[currentIndex++] = a[leftCrawler++];
while (rightCrawler < right)
temp[currentIndex++] = a[rightCrawler++];
// 将 temp 复制回 a
for (int i = 0; i < temp.length; i++)
a[left + i] = temp[i];
}
private static void mergeSort(int[] a, int left, int right) {
if (right - left >= 2) {
int middle = left + (right - left) / 2;
mergeSort(a, left, middle);
mergeSort(a, middle, right);
merge(a, left, middle, right);
}
}
public static void mergeSort(int[] a) {
mergeSort(a, 0, a.length);
}
英文:
There are 3 errors in your code:
-
the merge loop does not include the element at
a[middle]
because you useleftCrawler < middle
instead of:while (leftCrawler <= middle && rightCrawler <= right)
-
the second loop
while (leftCrawler < middle)
must also be changed to:while (leftCrawler <= middle)
-
the loop to copy from
temp
back toa
uses an incorrect index intoa
. It should be:// copy temp into a for (int i = 0; i < temp.length; i++) a[left + i] = temp[i];
Note that the first error is rooted in the noxious convention used here where right
and middle
are included in the slices instead of excluded. Excluding the right boundaries allows for simpler code without any error prone +1
/-1
adjustments.
Here is a modified version:
// merge operation for merge sort
private static void merge(int[] a, int left, int middle, int right) {
int[] temp = new int[right - left];
int leftCrawler = left, rightCrawler = middle;
int currentIndex = 0;
while (leftCrawler < middle && rightCrawler < right) {
if (a[leftCrawler] < a[rightCrawler])
temp[currentIndex++] = a[leftCrawler++];
else
temp[currentIndex++] = a[rightCrawler++];
}
while (leftCrawler < middle)
temp[currentIndex++] = a[leftCrawler++];
while (rightCrawler < right)
temp[currentIndex++] = a[rightCrawler++];
// copy temp into a
for (int i = 0; i < temp.length; i++)
a[left + i] = temp[i];
}
private static void mergeSort(int[] a, int left, int right) {
if (right - left >= 2) {
int middle = left + (right - left) / 2;
mergeSort(a, left, middle);
mergeSort(a, middle, right);
merge(a, left, middle, right);
}
}
public static void mergeSort(int[] a) {
mergeSort(a, 0, a.length);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论