排序可视化工具中归并排序函数触发调用栈溢出错误的问题求助
解决归并排序递归栈溢出及功能异常问题
我一眼就看到几个导致栈溢出和功能异常的问题,咱们一步步来解决:
1. 全局变量+递归参数不匹配导致无限递归
你定义的mergeSort()函数没有参数,但递归调用时却传了mergeSort(el, low, mid)这类参数,同时还依赖全局的low和high变量。这会导致每次递归进入mergeSort时,始终使用全局的初始low=0和high=el.length-1,永远满足不了if (low >= high)的终止条件,进而无限递归,触发栈溢出。
修复方案:
把mergeSort改成带参数的函数,移除全局的low和high,在点击事件里传入初始边界值:
document.querySelector(".merge").addEventListener("click", function() { const bars = document.querySelectorAll(".bar"); mergeSort(bars, 0, bars.length - 1); }); // 带参数的mergeSort function mergeSort(arr, low, high){ if (low >= high){ return; } var mid = parseInt((low + high)/2); mergeSort(arr, low, mid); mergeSort(arr, mid + 1, high); merge(arr, low, mid, high); }
2. offsetHeight是只读属性,无法直接赋值
你在merge函数里尝试直接修改arr[k].offsetHeight,但offsetHeight是元素的只读属性,仅用于获取当前渲染后的高度,不能直接设置。要修改元素高度,应该用style.height属性,并且要带上单位(比如px)。
修复方案:
先把高度值转成数字进行比较,再通过style.height设置:
function merge(arr, low, mid, high){ var n = mid - low + 1; var m = high - mid; var leftArray = new Array(n); var rightArray = new Array(m); // 存储元素的高度数值(兼容style.height和offsetHeight) for(var i = 0; i < n; i++){ leftArray[i] = parseInt(arr[low + i].style.height) || arr[low + i].offsetHeight; } for(var j = 0; j < m; j++){ rightArray[j] = parseInt(arr[mid + 1 + j].style.height) || arr[mid + 1 + j].offsetHeight; } var i = 0; var j = 0; var k = low; while (i < n && j < m){ if (leftArray[i] <= rightArray[j]){ arr[k].style.height = `${leftArray[i]}px`; i++; }else{ arr[k].style.height = `${rightArray[j]}px`; j++; } k++; } while (i < n){ arr[k].style.height = `${leftArray[i]}px`; i++; k++; } while (j < m){ arr[k].style.height = `${rightArray[j]}px`; j++; } }
3. 额外优化:避免过时的DOM引用
原来的代码里var el = document.querySelectorAll(".bar");是全局的,多次点击可能会引用过时的DOM元素。把它放到点击事件回调里,每次点击都获取最新的元素集合,确保操作的是当前页面的元素。
修复后的完整代码
document.querySelector(".merge").addEventListener("click", function() { const bars = document.querySelectorAll(".bar"); mergeSort(bars, 0, bars.length - 1); }); function mergeSort(arr, low, high){ if (low >= high){ return; } const mid = Math.floor((low + high) / 2); // 用Math.floor比parseInt更稳妥 mergeSort(arr, low, mid); mergeSort(arr, mid + 1, high); merge(arr, low, mid, high); } function merge(arr, low, mid, high){ const n = mid - low + 1; const m = high - mid; const leftArray = []; const rightArray = []; // 收集左右数组的高度数值 for(let i = 0; i < n; i++){ const bar = arr[low + i]; leftArray.push(parseInt(bar.style.height) || bar.offsetHeight); } for(let j = 0; j < m; j++){ const bar = arr[mid + 1 + j]; rightArray.push(parseInt(bar.style.height) || bar.offsetHeight); } let i = 0, j = 0, k = low; while (i < n && j < m){ if (leftArray[i] <= rightArray[j]){ arr[k].style.height = `${leftArray[i]}px`; i++; }else{ arr[k].style.height = `${rightArray[j]}px`; j++; } k++; } while (i < n){ arr[k].style.height = `${leftArray[i]}px`; i++; k++; } while (j < m){ arr[k].style.height = `${rightArray[j]}px`; j++; k++; } }
这样修改后,递归的终止条件能正常触发,不会再出现栈溢出,同时也能正确修改元素高度实现排序可视化了。
内容的提问来源于stack exchange,提问作者Bayeroabdul
相关产品推荐
相关产品推荐

