根据Cormen的算法导论,我试图在Java中实现合并排序算法。我的代码(下面)的问题是主数组在合并步骤中复制了一些条目。
有人能够抓住我做错的事吗?
谢谢!
static void merge(int a[], int p, int q, int r)
{
int n1 = q - p;
int n2 = (r - q);
int [] left = new int[n1 + 1];
int [] right = new int[n2 + 1];
int pp = p;
int qq = q;
for(int i = 0; i < n1; i++)
{
left[i] = a[++pp];
}
for(int i = 0; i < n2; i++)
{
right[i] = a[++qq];
}
left[left.length-1] = Integer.MAX_VALUE;
right[right.length-1] = Integer.MAX_VALUE;
int i = 0;
int j = 0;
for(int k = p; k < r; k++)
{
if(left[i] <= right[j])
{
a[k] = left[i];
i++;
}
else
{
a[k] = right[j];
j++;
}
}
}
static int [] mergeSort(int a[], int p, int r)
{
if(p < r)
{
int q = (p + r)/2;
mergeSort(a, 1, q);
mergeSort(a, q + 1, r);
merge(a, p, q, r);
}
return a;
}
答案 0 :(得分:1)
我认为这是错误的(以及它在下一个循环中的兄弟姐妹):
left[i] = a[++pp];
你想从pp = p开始复制,所以在访问数组元素之前不要增加:
left[i] = a[pp++];
答案 1 :(得分:1)
这里的部分问题是书中的例子显然使用从1到长度的索引范围。如果你将索引范围从0更改为length-1会更简单,我在其余的答案中假设它。
在复制到左[]和右[]时使用后增量,由laune回答(因为索引范围为0到长度为1)。
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
public static int weeksInYear(int year) {
return new DateTime(DateTimeZone.forID("America/Los_Angeles"))
.withWeekyear(year + 1)
.withWeekOfWeekyear(1)
.minusWeeks(1)
.getWeekOfWeekyear();
}
主要问题是合并功能在合并期间没有检查它是否到达左或右运行的末尾。这可以通过将内部if更改为:
来修复 left[i] = a[pp++];
...
right[i] = a[qq++];
合并排序的递归调用应该是:
if (i < n1 && (j >= n2 || left[i] <= right[j]))
未显示,但对mergeSort的初始调用应为:
mergeSort(a, p, q);
mergeSort(a, q, r);
没有必要在左右分配额外的元素(因为索引范围是0到长度-1)。
mergeSort(a, 0, a.length);