问题描述
我正在尝试在Java中实现具有4路分区的合并排序算法,问题是它在算法的第85行中生成了ArrayIndexOutOfBoundsException
错误.代码如下,我基于Merge Sort
(传统算法)的2-way算法:
I am trying to implement the Merge Sort algorithm with 4-way partition in Java, the problem is that it generates an ArrayIndexOutOfBoundsException
error in line 85 of the algorithm. The code is as follows, I based on the 2-way algorithm of Merge Sort
(The traditional algorithm):
public static void mergeSort3WayRec(Integer[] gArray, int low, int high,
Integer[] destArray) {
if (high - low < 2) {
return;
}
int mid1 = low + ((high - low) / 4);
int mid2 = low + 2 * ((high - low) / 4) + 1;
int mid3 = low + 3 * ((high - low) / 4) + 2;
mergeSort3WayRec(destArray, low, mid1, gArray);
mergeSort3WayRec(destArray, mid1, mid2, gArray);
mergeSort3WayRec(destArray, mid2, mid3, gArray);
mergeSort3WayRec(destArray, mid3, high, gArray);
merge(destArray, low, mid1, mid2, mid3, high, gArray);
}
public static void merge(Integer[] gArray, int low, int mid1, int mid2, int mid3, int high,
Integer[] destArray) {
int i = low, j = mid1, k = mid2, l = mid3, m = high;
while ((i < mid1) && (j < mid2) && (k < mid3) && (l < high)) {
if (gArray[i].compareTo(gArray[j]) < 0) {
if (gArray[i].compareTo(gArray[k]) < 0) {
if (gArray[i].compareTo(gArray[l]) < 0) {
destArray[m++] = gArray[i++];
} else {
destArray[m++] = gArray[l++];
}
} else {
destArray[m++] = gArray[k++];
}
} else {
if (gArray[j].compareTo(gArray[k]) < 0) {
if (gArray[j].compareTo(gArray[l]) < 0) {
destArray[m++] = gArray[j++];
} else {
destArray[m++] = gArray[l++];
}
} else {
if (gArray[k].compareTo(gArray[l]) < 0) {
destArray[m++] = gArray[k++];
} else {
destArray[m++] = gArray[l++];
}
}
}
}
while ((i < mid1) && (j < mid2)) {
if (gArray[i].compareTo(gArray[j]) < 0) {
destArray[m++] = gArray[i++];
} else {
destArray[m++] = gArray[j++];
}
}
while ((j < mid2) && (k < mid3)) {
if (gArray[j].compareTo(gArray[k]) < 0) {
destArray[m++] = gArray[j++];
} else {
destArray[m++] = gArray[k++];
}
}
while ((k < mid3) && (l < high)) {
if (gArray[k].compareTo(gArray[l]) < 0) {
destArray[m++] = gArray[k++];
} else {
destArray[m++] = gArray[l++];
}
}
while ((i < mid1) && (k < mid3)) {
if (gArray[i].compareTo(gArray[k]) < 0) {
destArray[m++] = gArray[i++];
} else {
destArray[m++] = gArray[k++];
}
}
while ((i < mid1) && (l < high)) {
if (gArray[i].compareTo(gArray[l]) < 0) {
destArray[m++] = gArray[i++];
} else {
destArray[m++] = gArray[l++];
}
}
while ((j < mid2) && (l < high)) {
if (gArray[j].compareTo(gArray[l]) < 0) {
destArray[m++] = gArray[j++];
} else {
destArray[m++] = gArray[l++];
}
}
while (i < mid1) {
destArray[m++] = gArray[i++];
}
while (j < mid2) {
destArray[m++] = gArray[j++];
}
while (k < mid3) {
destArray[m++] = gArray[k++];
}
while (l < high) {
destArray[m++] = gArray[l++];
}
}
应注意,gArray
是在main方法中输入的原始数组的副本,此部分的代码如下:
It should be noted that gArray
is the copy of the original array entered in the main method, the code of this part is as follows:
public static void main(String args[]) {
Integer[] data = new Integer[]{ 45, -2, -45, 78,
30, -42, 10, 19, 73, 93, 80, 60, 2, 98, 85, 99 };
mergeSort3Way(data);
System.out.println("After 3 way merge sort: ");
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + " ");
}
}
public static void mergeSort3Way(Integer[] gArray) {
if (gArray == null) {
return;
}
Integer[] fArray = new Integer[gArray.length];
for (int i = 0; i < fArray.length; i++) {
fArray[i] = gArray[i];
}
mergeSort3WayRec(fArray, 0, gArray.length, gArray);
for (int i = 0; i < fArray.length; i++) {
gArray[i] = fArray[i];
}
}
我的问题是,如何解决此错误?另外,如果还有其他实现错误,那么我已经是使用这种算法的新手了.谢谢.
My question is, how can I solve this error? Also, if there is an additional implementation error, I am already a novice doing this type of algorithm.Thank you.
推荐答案
问题似乎是...,m =高,随后是destArray [m ++] =....
The problem appears to be ... , m = high, followed later by destArray[m++] = ... .
在合并中,当4向合并到达4次运行之一的末尾时,它应降为3向合并.为了避免重复代码,您需要将索引移动到low,mid1,mid2,并使用mid3或high作为子数组从mid2开始的结尾.当3种方式的合并到达其中一个运行的末尾时,应将其降至2种方式的合并,然后降低至1种方式的副本.
In the merge, when the 4 way merge reaches the end of one of the 4 runs, it should drop down to a 3 way merge. In order to avoid duplicating code, you'll need to move the indexes to low, mid1, mid2, and use mid3 or high for the end of the sub-array starting at mid2. When the 3 way merge reaches the end of one of the runs, it should drop down to a 2 way merge, then drop down to a 1 way copy.
在归并排序中,如果高低< 4,您可能只想进行冒泡排序比较并交换为高-低== 3或高-低== 2.
In the mergesort, if high-low < 4, you may want to just do bubble sort compare and swaps for high - low == 3 or high - low == 2.
假设高低< 4是分开处理的,然后用于均匀地设置内部索引(较小的行在左侧):
Assuming high-low < 4 is handled separately, then for setting the inner indexes somewhat evenly (smaller runs on left):
int mid1 = low +(high+0-low)/4;
int mid2 = mid1+(high+1-low)/4;
int mid3 = mid2+(high+2-low)/4;
使用一对相互递归的函数来避免回写和展开"合并逻辑的自上而下4方式合并排序的示例代码.此方法比执行许多条件操作要快,但是我认为主要的性能改进是由于对小批量运行使用了插入排序.在这种情况下,Java中没有"goto"是一个问题,因为避免重复代码的方法是在合并例程中设置并测试最小运行"变量.
Example code for top down 4 way merge sort using a pair of mutually recursive functions to avoid copy back, and "unfolded" merge logic. This method is faster than doing a lot of conditionals, but I think the main performance improvement is due to using insertion sort for small runs. This is case where not having a "goto" in Java is an issue, as the work around to avoid duplicate code is to set and test a "smallest run" variable in the merge routine.
static final int MINSIZE = 32; // must be >= 3
static void InsertionSort(Integer a[], int ll, int rr)
{
int i = ll+1;
int j;
Integer t;
while(i < rr){
t = a[i];
j = i;
while((j > ll) && a[j-1].compareTo(t)> 0){
a[j] = a[j-1];
j -= 1;}
a[j] = t;
i += 1;}
}
public static void MergeSort(Integer[] a) // entry function
{
if(a.length < 2) // if size < 2 return
return;
Integer[] b = new Integer[a.length];
MergeSortAtoA(a, b, 0, a.length);
}
static void MergeSortAtoA(Integer[] a, Integer[] b, int ll, int rr)
{
if(rr - ll <= MINSIZE){
InsertionSort(a, ll, rr);
return;}
int m1 = ll+(rr+0-ll)/4;
int m2 = m1+(rr+1-ll)/4;
int m3 = m2+(rr+2-ll)/4;
MergeSortAtoB(a, b, ll, m1);
MergeSortAtoB(a, b, m1, m2);
MergeSortAtoB(a, b, m2, m3);
MergeSortAtoB(a, b, m3, rr);
Merge(b, a, ll, m1, m2, m3, rr);
}
static void MergeSortAtoB(Integer[] a, Integer[] b, int ll, int rr)
{
if(rr - ll <= MINSIZE){
System.arraycopy(a, ll, b, ll, rr-ll);
InsertionSort(b, ll, rr);
return;}
int m1 = ll+(rr+0-ll)/4;
int m2 = m1+(rr+1-ll)/4;
int m3 = m2+(rr+2-ll)/4;
MergeSortAtoA(a, b, ll, m1);
MergeSortAtoA(a, b, m1, m2);
MergeSortAtoA(a, b, m2, m3);
MergeSortAtoA(a, b, m3, rr);
Merge(a, b, ll, m1, m2, m3, rr);
}
static void Merge(Integer[] a, Integer[] b, int ll, int m1, int m2, int m3, int rr) {
int bb = ll; // b[] index
int a0 = ll; // a[] indexes
int a1 = m1;
int a2 = m2;
int a3 = m3;
while(true){ // 4 way merge
int sr; // smallest run
if(a[a0].compareTo(a[a1]) <= 0){
if(a[a2].compareTo(a[a3]) <= 0){
if(a[a0].compareTo(a[a2]) <= 0){
sr = 0;}
else{
sr = 2;}}
else{
if(a[a0].compareTo(a[a3]) <= 0){
sr = 0;}
else{
sr = 3;}}}
else{
if(a[a2].compareTo(a[a3]) <= 0){
if(a[a1].compareTo(a[a2]) <= 0){
sr = 1;}
else{
sr = 2;}}
else{
if(a[a1].compareTo(a[a3]) <= 0){
sr = 1;}
else{
sr = 3;}}}
if(sr == 0){
b[bb] = a[a0];
bb++;
a0++;
if(a0 < m1)
continue;
a0 = a1;
a1 = a2;
a2 = a3;
m1 = m2;
m2 = m3;
m3 = rr;
break;}
if(sr == 1){
b[bb] = a[a1];
bb++;
a1++;
if(a1 < m2)
continue;
a1 = a2;
a2 = a3;
m2 = m3;
m3 = rr;
break;}
if(sr == 2){
b[bb] = a[a2];
bb++;
a2++;
if(a2 < m3)
continue;
a2 = a3;
m3 = rr;
break;}
else{ // sr == 3
b[bb] = a[a3];
bb++;
a3++;
if(a3 < rr)
continue;
break;}
}
while(true){ // 3 way merge
int sr; // smallest run
if(a[a0].compareTo(a[a1]) <= 0){
if(a[a0].compareTo(a[a2]) <= 0){
sr = 0;}
else{
sr = 2;}}
else{
if(a[a1].compareTo(a[a2]) <= 0){
sr = 1;}
else{
sr = 2;}}
if(sr == 0){
b[bb] = a[a0];
bb++;
a0++;
if(a0 < m1)
continue;
a0 = a1;
a1 = a2;
m1 = m2;
m2 = m3;
break;}
if(sr == 1){
b[bb] = a[a1];
bb++;
a1++;
if(a1 < m2)
continue;
a1 = a2;
m2 = m3;
break;}
else{ // sr == 2
b[bb] = a[a2];
bb++;
a2++;
if(a2 < m3)
continue;
break;}
}
while(true){ // 2 way merge
if(a[a0].compareTo(a[a1]) <= 0){
b[bb] = a[a0];
bb++;
a0++;
if(a0 < m1)
continue;
a0 = a1;
m1 = m2;
break;}
else{
b[bb] = a[a1];
bb++;
a1++;
if(a1 < m2)
continue;
break;}
}
System.arraycopy(a, a0, b, bb, m1-a0); // 1 way copy
}
修复了chqrlie版本的代码.
Fixed version chqrlie's code.
public static void merge(Integer[] gArray, int low, int mid1, int mid2, int mid3, int high,
Integer[] destArray)
{
int i = low, j = mid1, k = mid2, l = mid3, m = low;
while (m < high) {
if (i < mid1 && (j >= mid2 || gArray[i].compareTo(gArray[j]) <= 0)) {
if (k >= mid3 || gArray[i].compareTo(gArray[k]) <= 0) {
if (l >= high || gArray[i].compareTo(gArray[l]) <= 0) {
destArray[m++] = gArray[i++];
} else {
destArray[m++] = gArray[l++];
}
} else {
if (k < mid3 && (l >= high || gArray[k].compareTo(gArray[l]) <= 0)) {
destArray[m++] = gArray[k++];
} else {
destArray[m++] = gArray[l++];
}
}
} else {
if (j < mid2 && (k >= mid3 || gArray[j].compareTo(gArray[k]) < 0)) {
if (l >= high || gArray[j].compareTo(gArray[l]) < 0) {
destArray[m++] = gArray[j++];
} else {
destArray[m++] = gArray[l++];
}
} else {
if (k < mid3 && (l >= high || gArray[k].compareTo(gArray[l]) < 0)) {
destArray[m++] = gArray[k++];
} else {
destArray[m++] = gArray[l++];
}
}
}
}
}
public static void mergeSort4WayRec(Integer[] gArray, int low, int high,
Integer[] tempArray) {
if (high - low < 2) {
return;
}
int mid1 = low + (high + 0 - low) / 4;
int mid2 = mid1 + (high + 1 - low) / 4;
int mid3 = mid2 + (high + 2 - low) / 4;
mergeSort4WayRec(tempArray, low, mid1, gArray);
mergeSort4WayRec(tempArray, mid1, mid2, gArray);
mergeSort4WayRec(tempArray, mid2, mid3, gArray);
mergeSort4WayRec(tempArray, mid3, high, gArray);
merge(tempArray, low, mid1, mid2, mid3, high, gArray);
}
public static void mergeSort4Way(Integer[] gArray) {
if (gArray != null) {
Integer[] tempArray = new Integer[gArray.length];
for (int i = 0; i < gArray.length; i++) {
tempArray[i] = gArray[i];
}
mergeSort4WayRec(gArray, 0, gArray.length, tempArray);
}
}
public static void main(String[] args) {
Integer[] a = new Integer[1024*1024];
Random r = new Random();
for(int i = 0; i < a.length; i++)
a[i] = r.nextInt();
long bgn, end;
bgn = System.currentTimeMillis();
mergeSort4Way(a);
end = System.currentTimeMillis();
for(int i = 1; i < a.length; i++){
if(a[i-1] > a[i]){
System.out.println("failed");
break;
}
}
System.out.println("milliseconds " + (end-bgn));
}
这篇关于如何在没有错误ArrayIndexOutOfBoundsException的情况下实现具有4路分区的合并排序算法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!