
本文详解归并排序 merge 方法中因循环边界与索引计算错误导致 ArrayIndexOutOfBoundsException 的根本原因,并提供修正后的标准实现、关键注意事项及可运行示例。
本文详解归并排序 `merge` 方法中因循环边界与索引计算错误导致 `arrayindexoutofboundsexception` 的根本原因,并提供修正后的标准实现、关键注意事项及可运行示例。
归并排序的核心在于“分而治之”:先递归拆分数组,再在 merge 步骤中将两个已排序的子数组合并为一个有序数组。但初学者常在 merge 函数的子数组复制阶段出错——问题不在于算法思想,而在于对索引边界的机械套用。
观察原代码的关键缺陷:
for (int i = 0; i < Arr.length; i++) { // ❌ 错误:遍历整个原数组长度(8),但左右子数组容量远小于此
if (i <= mid) {
arr_left[i] = Arr[low + i]; // ✅ 左子数组:索引范围 [low, mid] → 共 mid-low+1 个元素
} else {
arr_right[i] = Arr[mid + 1 + i]; // ❌ 危险!当 i=4 时,mid+1+i = 3+1+4 = 8 → 超出 Arr.length-1(最大7)
}
}此处存在三重逻辑错误:
-
循环范围错误:
i不应遍历Arr.length(8),而应分别遍历左右子数组的实际长度; -
右子数组索引偏移错误:
arr_right[i]的i是右子数组的局部索引(从 0 开始),但Arr[mid + 1 + i]中的i沿用了全局循环变量,导致越界; -
条件判断失效:
if (i 仅适用于 <code>low==0的特例,当low > 0(如递归深层调用)时完全失效。
✅ 正确做法是:独立遍历左右子数组的有效区间,使用各自的起始位置和长度:
public static void merge(int[] arr, int low, int mid, int high) {
// 创建左右子数组(长度严格对应实际元素个数)
int[] left = new int[mid - low + 1];
int[] right = new int[high - mid]; // 注意:high - mid,非 high - mid + 1
// 复制左半部分:arr[low...mid] → left[0...left.length-1]
for (int i = 0; i < left.length; i++) {
left[i] = arr[low + i];
}
// 复制右半部分:arr[mid+1...high] → right[0...right.length-1]
for (int j = 0; j < right.length; j++) {
right[j] = arr[mid + 1 + j];
}
System.out.println("Left: " + Arrays.toString(left));
System.out.println("Right: " + Arrays.toString(right));
}? 关键点说明:
left.length = mid - low + 1:覆盖[low, mid](含端点),共mid-low+1个元素;right.length = high - mid:覆盖[mid+1, high](含端点),共high-(mid+1)+1 = high-mid个元素;- 复制时使用
left[i] = arr[low + i]和right[j] = arr[mid + 1 + j],确保局部索引i/j从 0 开始,与目标数组容量严格对齐。
? 额外重要提醒:
- 完整的归并排序需包含递归分解(
mergeSort(arr, low, mid)和mergeSort(arr, mid+1, high))与双指针合并逻辑,当前merge仅完成数据分割; - 始终验证边界:
low ≤ mid ,且 <code>mid应取(low + high) / 2(避免大数组整数溢出,推荐low + (high - low) / 2); - 使用
Arrays.copyOfRange(arr, from, to)可简化复制(to为exclusive),例如:int[] left = Arrays.copyOfRange(arr, low, mid + 1);int[] right = Arrays.copyOfRange(arr, mid + 1, high + 1);
遵循上述修正后,代码即可稳定运行,为后续合并步骤奠定坚实基础。

















