我一直在研究这种三向合并排序算法,该算法基于我的常规合并排序代码;但是,它的排序不正确,因此我认为我的代码可能存在小错误。有什么帮助吗?我已经研究了3个小时的代码以尝试发现问题,但是事实证明这很困难。
public class TriMergeSort {
void merge(int arr[], int low, int mid1, int mid2, int high) {
int sizeA = mid1 - low + 1;
int sizeB = mid2 - mid1;
int sizeC = high - mid2;
int A[] = new int[sizeA];
int B[] = new int[sizeB];
int C[] = new int[sizeC];
for (int i = 0; i < sizeA; i++)
A[i] = arr[low + i];
for (int j = 0; j < sizeB; j++)
B[j] = arr[mid1 + j + 1];
for (int x = 0; x < sizeC; x++)
C[x] = arr[mid2 + x + 1];
int i = 0, j = 0, x = 0;
int k = low;
while (i < sizeA && j < sizeB && x < sizeC) {
if (A[i] < B[j] && A[i] < C[x]) {
arr[k] = A[i];
i++;
} else
if (A[i] >= B[j] && B[j] < C[x]) {
arr[k] = B[j];
j++;
} else
if (A[i] > C[x] && B[j] >= C[x]) {
arr[k] = C[x];
x++;
}
k++;
}
while (i < sizeA) {
arr[k] = A[i];
i++;
k++;
}
while (j < sizeB) {
arr[k] = B[j];
j++;
k++;
}
while (x < sizeC) {
arr[k] = C[x];
x++;
k++;
}
}
void sort(int arr[], int low, int high) {
if (low < high) {
int mid1 = low + ((high - low) / 3);
int mid2 = low + 2 * ((high - low) / 3) + 1;
sort(arr, low, mid1);
sort(arr, mid1 + 1, mid2);
sort(arr, mid2 + 1, high);
merge(arr, low, mid1, mid2, high);
}
}
static void print(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i)
System.out.print(arr[i] + " ");
System.out.println();
}
public static void main(String args[]) {
int arr[] = { 15, 2, 6, 7, 55, 0, 28, 41, 12 };
TriMergeSort test = new TriMergeSort();
test.sort(arr, 0, arr.length - 1);
print(arr);
}
}
答案 0 :(得分:1)
问题中张贴的代码可以正常工作。您没有发布遇到问题的三向合并代码。
请注意,不要将high
作为索引传递到要排序的切片中的最后一项,而应该将第一个元素的索引传递到切片之外。这样可以简化代码,而不会造成混乱和容易出错的+1
/ -1
调整。
这是修改后的版本:
public class MergeSort {
void merge(int arr[], int low, int mid, int high) {
int sizeA = mid - low;
int sizeB = high - mid;
int A[] = new int[sizeA];
int B[] = new int[sizeB];
for (int i = 0; i < sizeA; i++)
A[i] = arr[low + i];
for (int j = 0; j < sizeB; j++)
B[j] = arr[mid + j];
int i = 0, j = 0;
int k = low;
while (i < sizeA && j < sizeB) {
if (A[i] <= B[j]) {
arr[k++] = A[i++];
} else {
arr[k++] = B[j++];
}
}
while (i < sizeA) {
arr[k++] = A[i++];
}
while (j < sizeB) {
arr[k++] = B[j++];
}
}
void sort(int arr[], int low, int high) {
if (high - low >= 2) {
int mid = low + (high - low) / 2;
sort(arr, low, mid);
sort(arr, mid, high);
merge(arr, low, mid, high);
}
}
static void print(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String args[]) {
int arr[] = { 15, 2, 6, 7, 55, 0, 28, 41, 12, 10, 59 };
MergeSort test = new MergeSort();
test.sort(arr, 0, arr.length);
print(arr);
}
}
要将其转换为3向合并版本,sort3
必须遵循以下步骤:
low
到mid1 = low + (high - low)/3
,第二个切片从mid1
到mid2 = low + (high - low)*2/3
,第三个切片排除mid2
至high
。merge3(arr, low, mid1, mid2, high)
编辑:merge
类中的TriMergeSort
函数缺少3个循环,这些3个循环会在3个初始切片之一耗尽后合并2个切片。这解释了为什么数组未正确排序。在三向合并循环之后,您应该具有:
while (i < sizeA && j < sizeB) {
...
}
while (i < sizeA && x < sizeC) {
...
}
while (j < sizeB && x < sizeC) {
...
}
为避免所有这些重复的循环,可以将对索引值的测试组合到一个循环主体中:
public class TriMergeSort {
void merge(int arr[], int low, int mid1, int mid2, int high) {
int sizeA = mid1 - low;
int sizeB = mid2 - mid1;
int sizeC = high - mid2;
int A[] = new int[sizeA];
int B[] = new int[sizeB];
int C[] = new int[sizeC];
for (int i = 0; i < sizeA; i++)
A[i] = arr[low + i];
for (int j = 0; j < sizeB; j++)
B[j] = arr[mid1 + j];
for (int k = 0; k < sizeC; k++)
C[k] = arr[mid2 + k];
int i = 0, j = 0, k = 0;
while (low < high) {
if (i < sizeA && (j >= sizeB || A[i] <= B[j])) {
if (k >= sizeC || A[i] <= C[k]) {
arr[low++] = A[i++];
} else {
arr[low++] = C[k++];
}
} else {
if (j < sizeB && (k >= sizeC || B[j] <= C[k])) {
arr[low++] = B[j++];
} else {
arr[low++] = C[k++];
}
}
}
}
void sort(int arr[], int low, int high) {
if (high - low >= 2) {
int mid1 = low + (high - low) / 3;
int mid2 = low + (high - low) * 2 / 3;
sort(arr, low, mid1);
sort(arr, mid1, mid2);
sort(arr, mid2, high);
merge(arr, low, mid1, mid2, high);
}
}
static void print(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String args[]) {
int arr[] = { 15, 2, 6, 7, 55, 0, 28, 41, 12 };
TriMergeSort test = new TriMergeSort();
test.sort(arr, 0, arr.length);
print(arr);
}
}
上面的while
循环可以进一步简化,但可读性较差:
while (low < high) {
if (i < sizeA && (j >= sizeB || A[i] <= B[j])) {
arr[low++] = (k >= sizeC || A[i] <= C[k]) ? A[i++] : C[k++];
} else {
arr[low++] = (j < sizeB && (k >= sizeC || B[j] <= C[k])) ? B[j++] : C[k++];
}
}
甚至更进一步:
while (low < high) {
arr[low++] = (i < sizeA && (j >= sizeB || A[i] <= B[j])) ?
((k >= sizeC || A[i] <= C[k]) ? A[i++] : C[k++]) :
(j < sizeB && (k >= sizeC || B[j] <= C[k])) ? B[j++] : C[k++];
}