简易归并排序(mergeSort)代码输出错误,请求定位Bug
排查归并排序中的全局变量问题导致的合并错误
你怀疑闭包的问题其实是个误判,真正搞砸你排序结果的是未声明的全局变量!咱们一步步拆解问题:
问题根源:全局变量j被递归覆盖
在你的mergeSort函数里,这一行代码:
j = Math.floor((end+start)/2);
没有用var、let或const声明j,导致它变成了全局变量。递归调用的时候,每一层都会修改这个全局的j,直接打乱了上层递归的预期逻辑。
拿你的测试用例[300,200,100]来说,执行流程的bug点:
- 第一次调用
mergeSort(A,0,2),计算出全局j=1,然后递归处理mergeSort(A,0,1) - 进入
mergeSort(A,0,1)后,计算出新的全局j=0,递归处理完两个单元素后,执行merge把[300,200]改成了[200,300] - 回到第一次调用的
mergeSort,此时全局j已经被改成0了!接下来执行mergeSort(A,(j+1),end)时,实际调用的是mergeSort(A,1,2)(而不是预期的mergeSort(A,2,2)) - 这就导致后续没有合并已经排好的
[200,300]和[100],反而去处理[300,100],最终得到错误的[200,100,300]
修复方案:把j声明为局部变量
只需要给mergeSort里的j加上let(推荐用let,块级作用域更安全),让它成为当前递归层的局部变量:
let j = Math.floor((end+start)/2);
修复后的完整代码
function mergeSort(A, start, end) { console.log("Sorting " + A + " between " + start + " and " + end) if (start == end) { console.log("Reached singleton element: " + A[start]) return; } // 声明为局部变量 let j = Math.floor((end + start)/2); mergeSort(A, start, j); console.log("Sorted " + A + " between " + start + " and " + j + ". Now sorting between " + (j+1) + " and " + end) mergeSort(A, (j+1), end); merge(A, start, (j+1), end); return A } function merge(A, s, p, e) { var i = s; var j = p; var finalArray = []; while (i < p && j < e+1) { if (A[i] <= A[j]) { finalArray.push(A[i]); i++ } else { finalArray.push(A[j]); j++ } } // 简化剩余元素的添加逻辑 while (j < e+1 ) { finalArray.push(A[j]); j++ } while (i < p ) { finalArray.push(A[i]); i++ } for(var q = s; q < e+1; q++){ A[q] = finalArray[q - s] } } A = [300,200, 100] mergeSort(A, 0, (A.length-1)); console.log(A); // 输出 [100, 200, 300]
我顺便把merge里的finalArray索引计算改成了push,逻辑更清晰,避免索引计算出错。
额外提醒
递归函数里一定要注意变量的作用域,全局变量会让递归的每一层互相干扰,这是递归开发中很容易踩的坑!
内容的提问来源于stack exchange,提问作者Piyush Ahuja
相关产品推荐
相关产品推荐

