
本文详解归并排序 merge 方法中因循环边界与索引计算错误导致 ArrayIndexOutOfBoundsException 的根本原因,并提供修正后的标准实现、关键注意事项及可运行示例。
本文详解归并排序 `merge` 方法中因循环边界与索引计算错误导致 `arrayindexoutofboundsexception` 的根本原因,并提供修正后的标准实现、关键注意事项及可运行示例。
归并排序的核心在于“分而治之”:先递归拆分数组,再在 merge 步骤中将两个已排序的子数组合并为一个有序数组。但初学者常在 merge 函数的子数组复制阶段出错——问题不在于算法思想,而在于对索引边界的机械套用。
观察原代码的关键缺陷:
for (int i = 0; i <p>此处存在<strong>三重逻辑错误</strong>:</p><ol>
<li>
<strong>循环范围错误</strong>:<code>i</code> 不应遍历 <code>Arr.length</code>(8),而应分别遍历左右子数组的实际长度;</li>
<li>
<strong>右子数组索引偏移错误</strong>:<code>arr_right[i]</code> 的 <code>i</code> 是右子数组的局部索引(从 0 开始),但 <code>Arr[mid + 1 + i]</code> 中的 <code>i</code> 沿用了全局循环变量,导致越界;</li>
<li>
<strong>条件判断失效</strong>:<code>if (i 仅适用于 <code>low==0</code> 的特例,当 <code>low > 0</code>(如递归深层调用)时完全失效。</code>
</li>
</ol><p>✅ 正确做法是:<strong>独立遍历左右子数组的有效区间</strong>,使用各自的起始位置和长度:</p><pre class="brush:php;toolbar:false;">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 <blockquote>
<p>? 关键点说明:</p>
<ul>
<li>
<code>left.length = mid - low + 1</code>:覆盖 <code>[low, mid]</code>(含端点),共 <code>mid-low+1</code> 个元素;</li>
<li>
<code>right.length = high - mid</code>:覆盖 <code>[mid+1, high]</code>(含端点),共 <code>high-(mid+1)+1 = high-mid</code> 个元素;</li>
<li>复制时使用 <code>left[i] = arr[low + i]</code> 和 <code>right[j] = arr[mid + 1 + j]</code>,确保局部索引 <code>i/j</code> 从 0 开始,与目标数组容量严格对齐。</li>
</ul>
</blockquote><p>? <strong>额外重要提醒</strong>:</p>
- 完整的归并排序需包含递归分解(
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);
遵循上述修正后,代码即可稳定运行,为后续合并步骤奠定坚实基础。










