void merge(int A[], int p, int q, int r) {
int *tmpL, *tmpR;
int boundary;
int n1, n2;
int i, j, k;
n1 = q - p + 1;
n2 = r - q;
tmpL = (int *)malloc(sizeof(int) * (n1 + 1));
tmpR = (int *)malloc(sizeof(int) * (n2 + 1));
for (i = 0; i < n1; i++)
tmpL[i] = A[p + i];
for (j = 0; j < n2; j++)
tmpR[j] = A[q + j + 1];
boundary = tmpL[n1 - 1] > tmpR[n2 - 1] ? tmpL[n1 - 1] + 1 : tmpR[n2 - 1] + 1;
tmpL[n1] = boundary;
tmpR[n2] = boundary;
i = 0;
j = 0;
for (k = p; k <= r; k++) {
if (tmpL[i] <= tmpR[j]) {
A[k] = tmpL[i];
i++;
} else {
A[k] = tmpR[j];
j++;
}
}
free(tmpL);
free(tmpR);
}
void merge_sort(int A[], int p, int r) {
int q;
if (p < r) {
q = (p + r) / 2;
merge_sort(A, p, q);
merge_sort(A, q + 1, r);
merge(A, p, q, r);
}
}
我无法完全理解这个无限边界代码boundary = tmpL[n1 - 1] > tmpR[n2 - 1] ? tmpL[n1 - 1] + 1 : tmpR[n2 - 1] + 1;
谢谢 https://i.stack.imgur.com/UmyUg.png(蓝色圆圈)
这是一个条件语句A> B? C:D
。
如果A> B
为真,则评估C,否则评估D。
但是我仍然不了解边界部分。
这与添加两个while循环来处理时(其中一半有剩余元素并将它们附加到新数组的末尾)一样吗?
如果我不将它们初始化为无限边界,则可能会给我带来分割错误。
答案 0 :(得分:0)
merge()应该合并A中两个已排序的运行,从A [p]到A [q],以及从A [q + 1]到A [r](含)。创建了TmpL和TmpR,每个都在末尾留出1个额外元素的空间,以用作前哨值,该值大于TmpL或TmpR中的任何值。三元语句将边界设置为TmpL和TmpR中最后一个值中的较大者,然后将该值加1以创建存储在TmpL和TmpR末尾的标记值。这样就无需检查索引“ i”或“ j”以查看是否已达到TmpL或TmpR的末尾,在这种情况下,其余的TmpR或TmpL将被复制回A []。
对于大多数编程语言,该代码可以仅将边界设置为INT_MAX或包含文件limit.h中的其他最大值之一(或者对于C ++为climits),而不使用三元语句:
http://www.cplusplus.com/reference/climits
如果排序浮动或加倍,则可以将边界设置为无穷大。
出现分段错误的原因是,如果没有前哨值,则代码可能会超出导致故障的TmpL或TmpR的结尾。
此排序方法的一个问题是A []可能已经包含最大可能值,在这种情况下,该方法将失败。对于整数,将1加到最大值将换成最小值。
答案 1 :(得分:0)
代码对mergesort
使用一种通用方法,其中复制两个子数组,并在末尾添加一个额外的元素,其值设置为大于两个数组的最大值。
语句boundary = tmpL[n1 - 1] > tmpR[n2 - 1] ? tmpL[n1 - 1] + 1 : tmpR[n2 - 1] + 1;
尝试将值boundary
计算为1加上tmpL
或tmpR
的最大值,取决于哪个更大。它使用三元表达式,大致相当于编写:
if (tmpL[n1 - 1] > tmpR[n2 - 1])
boundary = tmpL[n1 - 1] + 1;
else
boundary = tmpR[n2 - 1] + 1;
然后,合并循环可以使用单个测试k <= r
停止循环,并且当{{时,i
等于n1
,j
等于n2
1}}到达k
。
这种方法在很多方面都被打破了:
r + 1
,则INT_MAX
的计算将溢出并导致未定义的行为。即使溢出不会引起致命的副作用,boundary
的值也将毫无意义,从而导致错误的结果或其他未定义的行为。boundary
不会覆盖尚未复制的值。我认为完全不应该教授这种方法。
这是没有这些缺点的另一种实现方式:
merge