归并排序mergeSort调换条件顺序引发数组越界与结果异常问题
问题核心:Java逻辑或运算符的短路求值规则
Java中||(逻辑或)运算符的求值规则是:只要左侧表达式结果为true,整个表达式就直接返回true,完全不会执行右侧的表达式,这是调换判断顺序后程序出错的根本原因。
两种判断顺序的执行差异
原正常条件的运行逻辑
原条件代码为:
if( j>end || (arr[i]<=arr[j] && i<=mid ))
这个顺序的执行路径没有越界风险:
- 首先判断右半段待合并区间的指针
j是否越界(也就是右半段的元素已经全部处理完成) - 只要
j>end成立,整个条件直接为真,进入取左半段剩余元素的分支,完全不会执行后面涉及数组访问的arr[i]<=arr[j]比较,从根源上避免j越界时还读取arr[j]的问题 - 只有当
j>end不成立(右半段还没处理完),才会进入右侧括号的判断逻辑,此时j是合法下标,访问arr[j]不会触发越界,最终能正常完成合并,打印出原数组加上排序后数组的完整输出2 4 3 1 1 2 3 4。
调换顺序后的异常原因
修改后的代码为:
if(( arr[i]<=arr[j] && i<=mid) || j>end )
调换||两侧的表达式顺序后,求值逻辑完全颠倒:
- 程序会优先计算左侧的
arr[i]<=arr[j],此时完全没有提前检查j是否越界 - 当右半段处理完成时,j会走到
end+1的位置:比如你测试用例的数组长度为4,合法下标最大为3,当end=3时,处理完右半段后j的值就是4。这时候程序还没来得及判断j>end,就直接尝试访问arr[4],自然抛出ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4,和你遇到的异常栈完全对应。 - 由于这个越界异常是在递归合并的过程中触发的,程序直接终止运行,main方法里mergeSort调用完成后的排序结果打印逻辑根本没有执行机会,所以你看到的输出只有最开始打印的原数组内容
2 4 3 1。 - 哪怕部分场景下没有触发越界,因为判断逻辑的优先级被打乱,原本应该优先处理的“某一段已经遍历完成、直接取另一段剩余元素”的分支,被延后到数组元素比较之后,也会导致合并逻辑错乱,最终输出错误的排序结果。
注意事项
归并排序的合并循环里,凡是涉及数组下标访问的判断,一定要把「指针是否越界」的检查放在最前面,利用短路特性保证越界判断先执行,再做实际的元素值比较,才能从根源上避免下标访问越界的问题。
内容的提问来源于stack exchange,提问作者Ray_Liu
相关产品推荐
相关产品推荐

