求助:JS实现Snail算法遇TypeError,无法处理大尺寸二维数组
Snail算法遍历数组问题排查与修复
问题描述
正在解决名为Snail的算法任务:给定n×n数组,返回从最外层到中间顺时针遍历的元素。编写的JavaScript函数在结果数组长度≤3时可正常返回[1,2,3,4],但处理更大数组时报错:Uncaught TypeError: Cannot read properties of undefined (reading '2'),down函数能获取到元素4,但无法访问5及之后的元素。
原代码:
function snail(array){ let arr=[...array] //copy of a passed array let result=[] //here function will add next blocks const y=arr.length; const x=arr[0].length //this is to measure size to stop while let cY=0,cX=0;//current Y axis and current X axis /*For the purpose of this function both axes start as 0(top left corner) and when going down is +1 instead of -1 as normally in math*/ while(result.length<=x*y){//this should go throw all of the blocks result.push(...arr[cY].splice(cX,1,null))//take block and replace it with null right()//search for a block - by default starts from right function } function right(){//goes right(next index of current array) if(arr[cY][cX+1]) {cX+=1} else{down()} } function down(){//goes down(next array of current index) if(arr[cY+1][cX]) {cY++} else{left()} } function left(){//goes left(previous index of current array) if(arr[cY][cX-1]) {cX--} else{up()} } function up(){//goes up(previous array of current index) if(arr[cY-1][cX]) {cY--} else{right()} } return result } console.log(snail([ [1,2,3],[8,9,4],[7,6,5]]))
错误原因分析
- 数组越界访问:当
cY+1超过数组长度时,arr[cY+1]会变为undefined,此时访问arr[cY+1][cX]直接触发类型错误。比如3×3数组遍历到元素4后,后续尝试向下时cY+1=3,arr[3]不存在,访问其下标必然报错。 - 终止条件错误:
while(result.length<=x*y)会导致循环多执行一次,当结果数组已收集完所有元素时,仍会尝试访问已处理的数组元素,引发错误。 - 元素判断逻辑缺陷:
if(arr[cY][cX+1])会把值为0或null的元素误判为“不存在”(二者在JS中为假值),导致方向切换逻辑混乱,无法正确定位下一个元素。
修复方案
- 修正循环终止条件:改为
while(result.length < x*y),确保收集完所有元素后立即停止循环。 - 安全边界检查:访问元素前先检查行/列是否在数组范围内,再判断元素是否未被标记为
null。 - 优化元素标记与判断:直接赋值
null标记已访问元素,判断时明确检查元素是否为null,避免假值干扰。
修复后的完整代码
function snail(array) { // 深拷贝二维数组,避免修改原输入 let arr = array.map(row => [...row]); let result = []; const totalElements = arr.length * arr[0].length; let cY = 0, cX = 0; while (result.length < totalElements) { // 收集当前元素并标记为已访问 result.push(arr[cY][cX]); arr[cY][cX] = null; // 按顺时针方向依次尝试切换 if (cX + 1 < arr[cY].length && arr[cY][cX + 1] !== null) { cX++; } else if (cY + 1 < arr.length && arr[cY + 1][cX] !== null) { cY++; } else if (cX - 1 >= 0 && arr[cY][cX - 1] !== null) { cX--; } else if (cY - 1 >= 0 && arr[cY - 1][cX] !== null) { cY--; } } return result; } console.log(snail([[1,2,3],[8,9,4],[7,6,5]])); // 输出 [1,2,3,4,5,6,7,8,9]
额外优化方案(更简洁的方向管理)
用数组存储顺时针方向,通过索引切换方向,代码可读性与维护性更强:
function snail(array) { if (!array.length || !array[0].length) return []; const arr = array.map(row => [...row]); const result = []; // 定义顺时针方向:右、下、左、上 const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]; let dirIndex = 0; let y = 0, x = 0; const total = arr.length * arr[0].length; for (let i = 0; i < total; i++) { result.push(arr[y][x]); arr[y][x] = null; // 计算下一个位置 let nextY = y + directions[dirIndex][0]; let nextX = x + directions[dirIndex][1]; // 检查下一个位置是否合法(在范围内且未被访问) if (nextY < 0 || nextY >= arr.length || nextX < 0 || nextX >= arr[0].length || arr[nextY][nextX] === null) { // 切换到下一个方向 dirIndex = (dirIndex + 1) % 4; nextY = y + directions[dirIndex][0]; nextX = x + directions[dirIndex][1]; } y = nextY; x = nextX; } return result; }
内容的提问来源于stack exchange,提问作者Kuba Nowoszyński
相关产品推荐
相关产品推荐

