
本文详解 Merge Sort 实现中因循环范围与索引计算错误导致的 ArrayIndexOutOfBoundsException,通过分析典型错误代码,指出 i 超出子数组边界、误用全局长度遍历局部子数组等核心问题,并提供正确划分左右子数组的规范写法。
本文详解 merge sort 实现中因循环范围与索引计算错误导致的 `arrayindexoutofboundsexception`,通过分析典型错误代码,指出 `i` 超出子数组边界、误用全局长度遍历局部子数组等核心问题,并提供正确划分左右子数组的规范写法。
在实现归并排序(Merge Sort)的 merge 过程时,一个常见却隐蔽的错误是:用原数组长度控制循环,却将该循环变量直接用于索引大小受限的临时子数组。这正是提问者代码中抛出 ArrayIndexOutOfBoundsException: Index 8 out of bounds for length 8 的根本原因。
我们来逐步剖析原始代码的问题所在:
public static void merge(int[] Arr, int low, int mid, int high) {
int[] arr_left = new int[mid - low + 1]; // 左子数组长度:[low, mid] → 共 mid-low+1 个元素
int[] arr_right = new int[high - mid]; // 右子数组长度:[mid+1, high] → 共 high-mid 个元素
for (int i = 0; i <p>关键错误有两点:</p><ol>
<li>
<strong>循环范围错误</strong>:<code>for (int i = 0; i 应改为分别遍历两个子数组的<strong>各自有效索引范围</strong>,而非原数组总长;</code>
</li>
<li>
<strong>索引逻辑错位</strong>:<code>arr_left[i]</code> 和 <code>arr_right[i]</code> 中的 <code>i</code> 是全局循环变量,但子数组长度远小于原数组(如示例中 <code>arr_left.length = 4</code>, <code>arr_right.length = 4</code>),而 <code>i</code> 最大可达 <code>7</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]; // 注意:[mid+1, high] 共 high - mid 个元素
// ✅ 正确:用子数组长度驱动循环,i 仅在 left 合法范围内(0 ~ left.length-1)
for (int i = 0; i <blockquote>
<p>? 补充说明:示例输入 <code>arr = {38,27,43,10,56,27,18,32}</code>,<code>low=0</code>, <code>high=7</code>, <code>mid=3</code>(整数除法),则 </p>
<ul>
<li>
<code>left</code> 长度 = <code>3−0+1 = 4</code> → 对应 <code>[38,27,43,10]</code> </li>
<li>
<code>right</code> 长度 = <code>7−3 = 4</code> → 对应 <code>[56,27,18,32]</code><br>
若仍用 <code>i (即 <code>i ),当 <code>i=4</code> 时:<br>
→ <code>left[4]</code> 访问非法(<code>left</code> 最大索引为 <code>3</code>);<br>
→ <code>arr[mid+1+i] = arr[3+1+4] = arr[8]</code>,而 <code>arr</code> 索引最大为 <code>7</code>。</code></code>
</li>
</ul>
</blockquote><p>? <strong>总结与最佳实践</strong>:</p>
- 永远用目标数组的
.length控制其对应循环,避免跨数组复用索引变量; - 子数组切分务必验证边界:
left覆盖[low, mid],right覆盖[mid+1, high]; - 建议在开发中启用 IDE 调试器或添加日志(如
System.out.printf("i=%d, left.len=%d%n", i, left.length);)快速定位索引状态; - 完整 Merge Sort 还需后续的三指针合并逻辑(
i,j,k分别指向 left/right/原数组),但子数组构建阶段的健壮性是后续步骤的前提。
遵循以上原则,即可彻底规避此类低级但高频的数组越界异常,让归并排序的实现既正确又可维护。










