如何为回溯法求解数独的递归函数设置setTimeout延迟执行?
数独回溯求解器的可视化延迟问题
问题描述
我想展示回溯算法求解数独棋盘的过程,但不知道怎么让递归的solveBoard函数每隔500ms才执行一次。直接在函数里加setTimeout后,求解器完全失效,所有位置都被填成了9。首次调用是通过点击事件触发的,相关代码如下:
原求解函数代码
function solveBoard(board) { // 我试过把下面的代码都包在setTimeout里,但求解器会失效,所有位置都填9 let empty = findEmpty(board); if (!empty) return true; let row = empty[0]; let col = empty[1]; for (let i = 1; i < 10; i++) { board[row][col] = i; console.log(board[row][col]); document.getElementById(`${row}-${col}`).value = i; if (checkValid(board, row, col)) { if (solveBoard(board)) { return true; } } board[row][col] = 0; } return false; }
触发代码
solveBtn.addEventListener("click", () => { solveBoard(boardArray); });
问题原因
直接套setTimeout会破坏回溯的同步逻辑:
- 递归原本是同步执行,每一步的验证、回溯都依赖上一步的结果,但
setTimeout会把代码放到异步队列,导致还没等当前数字验证完成,就开始循环下一个数字,甚至递归调用下一层。 - 异步函数里的
return无法被上一层递归捕获,导致回溯的终止条件失效,最终所有位置都会被循环到最后一个数字9。
解决方案
把solveBoard改成异步函数,用async/await配合setTimeout实现延迟,确保每一步都等待延迟完成后再继续执行:
修改后的代码
// 封装一个延迟函数 function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function solveBoard(board) { let empty = findEmpty(board); if (!empty) return true; let row = empty[0]; let col = empty[1]; for (let i = 1; i < 10; i++) { // 填充当前数字并更新UI board[row][col] = i; document.getElementById(`${row}-${col}`).value = i; // 等待500ms await delay(500); if (checkValid(board, row, col)) { // 递归调用,等待递归完成 if (await solveBoard(board)) { return true; } } // 回溯,清空当前位置并更新UI board[row][col] = 0; document.getElementById(`${row}-${col}`).value = ""; // 回溯时也加延迟,让过程更清晰 await delay(500); } return false; } // 修改触发事件,适配异步函数 solveBtn.addEventListener("click", async () => { await solveBoard(boardArray); });
关键改动说明
- 延迟函数:用
Promise封装setTimeout,让await可以等待延迟完成,保证步骤的顺序执行。 - 异步递归:把
solveBoard声明为async函数,递归调用时用await等待结果,确保上一层递归能正确捕获返回值,维持回溯的逻辑正确性。 - UI同步:填充和回溯操作后都更新UI并等待延迟,让可视化过程连贯可观察。
- 触发逻辑:点击事件回调改为
async,等待solveBoard执行完成,避免异步操作导致的逻辑混乱。
这样修改后,就能看到数独求解的每一步过程,每隔500ms更新一次,同时保持回溯算法的正确性。
内容的提问来源于stack exchange,提问作者plauwh
相关产品推荐
相关产品推荐

