使用 Java 实现归并排序
Implementing Merge Sort with Java
我试图使用 java 实现合并排序,但它说:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at HelloWorld.merge(HelloWorld.java:42)
at HelloWorld.sort(HelloWorld.java:30)
at HelloWorld.sort(HelloWorld.java:28)
at HelloWorld.sort(HelloWorld.java:29)
at HelloWorld.sort(HelloWorld.java:28)
at HelloWorld.main(HelloWorld.java:10)
所以我试图在合并子例程中将原始数组复制到辅助数组中,我认为这是我用于辅助数组的长度搞砸了一切,不是 "r-l+1" 辅助数组的长度?
如果我将 100 作为 helper 数组的长度,代码会工作,但显然当原始数组的大小变大时它不会工作。
请帮助并提前致谢。
public class HelloWorld{
public static void main(String []args){
HelloWorld ms = new HelloWorld();
int arr[] = new int[]{4,3,0,1,3,2,4,20,13,22,10};
ms.sort(arr, 0, arr.length - 1);
ms.printArr(arr);
}
void printArr(int arr[])
{
int n = arr.length;
for(int i = 0; i<n; i++){
System.out.print(" "+arr[i]);
}
}
void sort(int arr[], int l, int r)
{
if(l<r){
int m = (l+r)/2;
sort(arr, l, m);
sort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void merge(int arr[], int l, int m, int r)
{
//find out helper array length
int helper[] = new int[r-l+1];
// Your code here
for(int i=l; i<=r; i++){
helper[i] = arr[i];
}
int i = l;
int k = l;
int j = m+1;
while(i<=m && j<=r){
if(helper[i]<=helper[j]){
arr[k]=helper[i];
i++;
}else{
arr[k]=helper[j];
j++;
}
k++;
}
while(i<=m){
arr[k]=helper[i];
i++;
k++;
}
}
}
您创建了一个大小为 r - l + 1
的数组
int helper[] = new int[r-l+1];
合并方法将与l = 3, m = 3, r = 4
一起执行
所以数组助手的大小为 r - l + 1 = 2 = [0, 0]
您的 for 循环从 l..r 运行
for(int i=l; i<=r; i++){
helper[i] = arr[i];
}
并且您尝试将值从 arr[3]
设置为 helper[3]
这是不可能的,因为 helper.length = 2
这就是 ArrayIndexOutOfBoundsException 发生的原因!您可以将对辅助索引的访问权限修改为 i - l
void merge(int arr[], int l, int m, int r) {
// find out helper array length
int helper[] = new int[r - l + 1];
// Your code here
System.arraycopy(arr, l, helper, 0, helper.length);
int i = l;
int k = l;
int j = m + 1;
while (i <= m && j <= r) {
if (helper[i - l] <= helper[j - l]) { // <---
arr[k] = helper[i - l]; // <---
i++;
} else {
arr[k] = helper[j - l]; // <---
j++;
}
k++;
}
while (i <= m) {
arr[k] = helper[i - l]; // <---
i++;
k++;
}
}
如果我理解您尝试正确实现合并排序算法的 MERGE 子例程的方式,那么您正在复制数组的相关部分(来自索引 l
, inclusive, 将 l
, inclusive) 索引到辅助数组中,然后使用复制到辅助数组中的数据修改原始数组。
在这种情况下,辅助数组的长度确实应该是 r-l+1
。但是,查看将原始数组部分复制到辅助数组的代码,您并没有在 for
循环中偏移索引。正确的做法是:
int helper[] = new int[r-l+1];
for (int i = l; i <= r; i++){
helper[i-l] = arr[i];
}
别忘了数组是零索引的!
不过,如果您绝对必须复制数组,我确实建议继续使用更现代的方法来复制数组。在这种情况下,我认为最适应的是系统调用 System.arraycopy(arr, l, helper, 0, r-l+1)
。如果您想了解更多关于在 Java 中复制数组(完全或部分)的不同方法,请查看 this answer。
我试图使用 java 实现合并排序,但它说:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at HelloWorld.merge(HelloWorld.java:42)
at HelloWorld.sort(HelloWorld.java:30)
at HelloWorld.sort(HelloWorld.java:28)
at HelloWorld.sort(HelloWorld.java:29)
at HelloWorld.sort(HelloWorld.java:28)
at HelloWorld.main(HelloWorld.java:10)
所以我试图在合并子例程中将原始数组复制到辅助数组中,我认为这是我用于辅助数组的长度搞砸了一切,不是 "r-l+1" 辅助数组的长度?
如果我将 100 作为 helper 数组的长度,代码会工作,但显然当原始数组的大小变大时它不会工作。
请帮助并提前致谢。
public class HelloWorld{
public static void main(String []args){
HelloWorld ms = new HelloWorld();
int arr[] = new int[]{4,3,0,1,3,2,4,20,13,22,10};
ms.sort(arr, 0, arr.length - 1);
ms.printArr(arr);
}
void printArr(int arr[])
{
int n = arr.length;
for(int i = 0; i<n; i++){
System.out.print(" "+arr[i]);
}
}
void sort(int arr[], int l, int r)
{
if(l<r){
int m = (l+r)/2;
sort(arr, l, m);
sort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void merge(int arr[], int l, int m, int r)
{
//find out helper array length
int helper[] = new int[r-l+1];
// Your code here
for(int i=l; i<=r; i++){
helper[i] = arr[i];
}
int i = l;
int k = l;
int j = m+1;
while(i<=m && j<=r){
if(helper[i]<=helper[j]){
arr[k]=helper[i];
i++;
}else{
arr[k]=helper[j];
j++;
}
k++;
}
while(i<=m){
arr[k]=helper[i];
i++;
k++;
}
}
}
您创建了一个大小为 r - l + 1
int helper[] = new int[r-l+1];
合并方法将与l = 3, m = 3, r = 4
一起执行
所以数组助手的大小为 r - l + 1 = 2 = [0, 0]
您的 for 循环从 l..r 运行
for(int i=l; i<=r; i++){
helper[i] = arr[i];
}
并且您尝试将值从 arr[3]
设置为 helper[3]
这是不可能的,因为 helper.length = 2
这就是 ArrayIndexOutOfBoundsException 发生的原因!您可以将对辅助索引的访问权限修改为 i - l
void merge(int arr[], int l, int m, int r) {
// find out helper array length
int helper[] = new int[r - l + 1];
// Your code here
System.arraycopy(arr, l, helper, 0, helper.length);
int i = l;
int k = l;
int j = m + 1;
while (i <= m && j <= r) {
if (helper[i - l] <= helper[j - l]) { // <---
arr[k] = helper[i - l]; // <---
i++;
} else {
arr[k] = helper[j - l]; // <---
j++;
}
k++;
}
while (i <= m) {
arr[k] = helper[i - l]; // <---
i++;
k++;
}
}
如果我理解您尝试正确实现合并排序算法的 MERGE 子例程的方式,那么您正在复制数组的相关部分(来自索引 l
, inclusive, 将 l
, inclusive) 索引到辅助数组中,然后使用复制到辅助数组中的数据修改原始数组。
在这种情况下,辅助数组的长度确实应该是 r-l+1
。但是,查看将原始数组部分复制到辅助数组的代码,您并没有在 for
循环中偏移索引。正确的做法是:
int helper[] = new int[r-l+1];
for (int i = l; i <= r; i++){
helper[i-l] = arr[i];
}
别忘了数组是零索引的!
不过,如果您绝对必须复制数组,我确实建议继续使用更现代的方法来复制数组。在这种情况下,我认为最适应的是系统调用 System.arraycopy(arr, l, helper, 0, r-l+1)
。如果您想了解更多关于在 Java 中复制数组(完全或部分)的不同方法,请查看 this answer。