我的合并排序实现有什么问题?
What's wrong with my merge sort implementation?
// 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);
}
因此,我认为问题可能出在我的合并操作上,但是我在以下数组 int[] a = {2, 5, 7, 15, 8, 9, 10}
上使用 left = 0
、middle = 4
和 right = a.length - 1
对其进行了测试并且合并操作完成了成功所需的操作。
我已经将我的 mergeSort 实现与各种网站上的实现进行了比较,我看不出有什么不同。我的 mergeSort 不会成功地对数组进行排序。我做错了什么?
问题可能出在您的副本上:
// copy temp into a
for(int i = 0; i < temp.length; i++)
a[i] = temp[i];
您可能想要的是(注意 left + i
):
// copy temp into a
for(int i = 0; i < temp.length; i++)
a[left + i] = temp[i];
(您的测试未检测到问题,因为 left
为 0。)
您的代码中有 3 个错误:
合并循环不包含 a[middle]
处的元素,因为您使用 leftCrawler < middle
而不是:
while (leftCrawler <= middle && rightCrawler <= right)
第二个循环while (leftCrawler < middle)
也必须改成:
while (leftCrawler <= middle)
从 temp
复制回 a
的循环使用了 a
中的错误索引。应该是:
// copy temp into a
for (int i = 0; i < temp.length; i++)
a[left + i] = temp[i];
请注意,第一个错误的根源在于此处使用的有害约定,其中 right
和 middle
包含在切片中而不是排除在外。排除正确的边界允许更简单的代码,而不会有任何容易出错的 +1
/-1
调整。
这是修改后的版本:
// 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);
}
// 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);
}
因此,我认为问题可能出在我的合并操作上,但是我在以下数组 int[] a = {2, 5, 7, 15, 8, 9, 10}
上使用 left = 0
、middle = 4
和 right = a.length - 1
对其进行了测试并且合并操作完成了成功所需的操作。
我已经将我的 mergeSort 实现与各种网站上的实现进行了比较,我看不出有什么不同。我的 mergeSort 不会成功地对数组进行排序。我做错了什么?
问题可能出在您的副本上:
// copy temp into a
for(int i = 0; i < temp.length; i++)
a[i] = temp[i];
您可能想要的是(注意 left + i
):
// copy temp into a
for(int i = 0; i < temp.length; i++)
a[left + i] = temp[i];
(您的测试未检测到问题,因为 left
为 0。)
您的代码中有 3 个错误:
合并循环不包含
a[middle]
处的元素,因为您使用leftCrawler < middle
而不是:while (leftCrawler <= middle && rightCrawler <= right)
第二个循环
while (leftCrawler < middle)
也必须改成:while (leftCrawler <= middle)
从
temp
复制回a
的循环使用了a
中的错误索引。应该是:// copy temp into a for (int i = 0; i < temp.length; i++) a[left + i] = temp[i];
请注意,第一个错误的根源在于此处使用的有害约定,其中 right
和 middle
包含在切片中而不是排除在外。排除正确的边界允许更简单的代码,而不会有任何容易出错的 +1
/-1
调整。
这是修改后的版本:
// 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);
}