当前位置: 首页 > news >正文

【路径算法】基于JavaScript实现IDA*算法,动态可视化展示路径规划过程

返回主目录:https://blog.csdn.net/eguid/article/details/154521483


返回总览:《寻路算法分类与适用场景详解,寻路算法与路径规划算法纵览:从BFS、A*到D与RRT》


IDA*算法简介

IDA*Iterative Deepening A*,迭代加深A*)是一种结合了迭代加深搜索和A*算法优点的启发式搜索算法。

核心思想

IDA*通过逐步增加f值限制的方式,重复执行深度优先搜索,直到找到目标节点。

算法流程

1. 设置初始阈值 = 起点的启发式值h(start)
2. 执行深度受限的DFS搜索:- 只扩展f值 ≤ 当前阈值的节点- f值 = g值(实际代价) + h值(启发式估计)
3. 如果找到目标,返回路径
4. 如果未找到,将阈值更新为本次迭代中超过阈值的最小f值
5. 重复步骤2-4,直到找到路径或确定无解

关键特点

优点:

  1. 内存效率极高 - 只存储当前路径,空间复杂度为O(d),d为路径深度
  2. 实现简单 - 算法逻辑清晰,易于实现
  3. 保证最优性 - 在启发函数可采纳时能找到最优解
  4. 无需维护开放列表 - 简化了数据结构

缺点:

  1. 节点重复扩展 - 每次迭代都可能重新探索之前访问过的节点
  2. 不适合动态环境 - 仅适用于静态路径规划问题
  3. 可能效率较低 - 在状态空间较大时,重复计算可能影响性能

伪代码示例

function IDAStar(start, goal) {let threshold = heuristic(start, goal);while (true) {let minExceeded = Infinity;let result = depthLimitedSearch(start, 0, threshold, goal);if (result.found) return result.path;if (minExceeded === Infinity) return null; // 无解threshold = minExceeded; // 增加阈值继续搜索}
}function depthLimitedSearch(node, g, threshold, goal) {let f = g + heuristic(node, goal);if (f > threshold) return {found: false, minCost: f};if (node === goal) return {found: true, path: [node]};let minCost = Infinity;for (let neighbor of getNeighbors(node)) {let result = depthLimitedSearch(neighbor, g + cost(node, neighbor), threshold, goal);if (result.found) {result.path.unshift(node);return result;}minCost = Math.min(minCost, result.minCost);}return {found: false, minCost: minCost};
}

A*算法的比较

特性A*算法IDA*算法
内存使用O(b^d) - 需要存储所有开放节点O(d) - 只存储当前路径
时间复杂度O(b^d)O(b^d) - 相同理论复杂度
实现难度中等简单
适用场景内存充足的环境内存受限的环境
节点扩展每个节点只扩展一次节点可能被多次扩展

适用场景

  1. 内存受限系统 - 嵌入式设备、游戏主机等
  2. 解谜游戏 - 十五数码、魔方等状态空间搜索
  3. 静态路径规划 - 已知的固定环境
  4. 学术研究 - 作为其他算法的基础和对比

实际应用示例

  • 十五数码问题 - 经典的拼图游戏求解
  • 魔方求解 - 寻找最优解步骤
  • 棋盘游戏 - 某些棋类游戏的走法生成
  • 静态地图导航 - 固定环境中的路径规划

IDA*算法通过牺牲时间效率来换取极低的内存消耗,在内存受限的场景中具有重要价值。它体现了计算机科学中经典的"时空权衡"思想。

IDA*算法路径规划可视化

下面我们将会实现IDA*算法并在Canvas上可视化其寻路过程。IDA*(迭代加深A*)算法结合了迭代加深搜索和A*算法的优点,通过逐步增加f值限制来寻找最优路径。

实现思路

  1. 创建网格环境,包含起点、终点和障碍物
  2. 实现IDA*算法核心逻辑
  3. 使用Canvas可视化算法执行过程
  4. 添加交互控制功能

下面是完整的实现代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>IDA*算法路径规划可视化</title><style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);color: #fff;min-height: 100vh;padding: 20px;}.container {max-width: 1000px;margin: 0 auto;background: rgba(0, 0, 0, 0.7);border-radius: 15px;padding: 25px;box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);}header {text-align: center;margin-bottom: 30px;padding-bottom: 20px;border-bottom: 2px solid rgba(255, 255, 255, 0.2);}h1 {font-size: 2.5rem;margin-bottom: 15px;text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);background: linear-gradient(to right, #ff7e5f, #feb47b);-webkit-background-clip: text;-webkit-text-fill-color: transparent;}.subtitle {font-size: 1.1rem;color: #e0e0e0;max-width: 800px;margin: 0 auto;line-height: 1.6;}.algorithm-info {background: rgba(30, 30, 50, 0.8);border-radius: 12px;padding: 20px;margin-bottom: 25px;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);}h2 {font-size: 1.6rem;margin-bottom: 15px;color: #ff7e5f;border-bottom: 2px solid rgba(255, 126, 95, 0.3);padding-bottom: 8px;}.algorithm-explanation {line-height: 1.7;}.algorithm-explanation p {margin-bottom: 12px;}.controls {display: grid;grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));gap: 12px;margin-bottom: 25px;}button {padding: 12px 18px;background: linear-gradient(to right, #ff7e5f, #feb47b);color: white;border: none;border-radius: 8px;cursor: pointer;font-weight: bold;transition: all 0.3s ease;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);}button:hover {transform: translateY(-3px);box-shadow: 0 6px 8px rgba(0, 0, 0, 0.3);}button:active {transform: translateY(1px);}button:disabled {background: #666;cursor: not-allowed;transform: none;box-shadow: none;}.canvas-container {display: flex;justify-content: center;margin-bottom: 20px;}canvas {border: 2px solid rgba(255, 255, 255, 0.2);border-radius: 8px;background: #0a0a1a;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);}.legend {display: flex;flex-wrap: wrap;gap: 20px;justify-content: center;margin-top: 20px;margin-bottom: 20px;}.legend-item {display: flex;align-items: center;}.legend-color {width: 20px;height: 20px;margin-right: 8px;border: 1px solid rgba(255, 255, 255, 0.3);border-radius: 4px;}.status {margin-top: 20px;padding: 15px;background: rgba(255, 126, 95, 0.2);border-radius: 8px;text-align: center;font-weight: bold;border-left: 5px solid #ff7e5f;}.performance {margin-top: 25px;padding: 15px;background: rgba(30, 30, 50, 0.8);border-radius: 8px;}.performance h3 {color: #ff7e5f;margin-bottom: 10px;}.performance-stats {display: grid;grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));gap: 15px;}.stat {background: rgba(0, 0, 0, 0.3);padding: 12px;border-radius: 6px;text-align: center;}.stat-value {font-size: 1.5rem;font-weight: bold;color: #ff7e5f;}.code-snippet {background: #1e1e2e;padding: 15px;border-radius: 8px;margin-top: 20px;overflow-x: auto;font-family: 'Courier New', monospace;border-left: 4px solid #ff7e5f;}footer {text-align: center;margin-top: 40px;padding-top: 20px;border-top: 1px solid rgba(255, 255, 255, 0.2);color: #aaa;font-size: 0.9rem;}</style>
</head>
<body><div class="container"><header><h1>IDA*算法路径规划可视化</h1><p class="subtitle">IDA*(迭代加深A*)算法通过逐步增加f值限制来寻找最优路径,结合了迭代加深搜索和A*算法的优点</p></header><section class="algorithm-info"><h2>IDA*算法简介</h2><div class="algorithm-explanation"><p><strong>核心思想:</strong>IDA*算法通过重复执行深度受限的深度优先搜索,每次迭代增加f值限制(f = g + h),直到找到目标节点。</p><p><strong>优点:</strong>内存效率极高(只存储当前路径),实现相对简单。</p><p><strong>缺点:</strong>无法处理动态环境,可能重复计算节点。</p><p><strong>适用场景:</strong>内存受限的静态环境路径规划,解谜游戏等。</p></div><div class="code-snippet"><pre>// IDA*算法核心伪代码
function IDA_STAR(start, goal) {threshold = heuristic(start, goal)while true {min_limit = ∞result = DFS(start, 0, threshold, goal)if result == FOUND return PATHif result == ∞ return NO_PATHthreshold = result}
}function DFS(node, g, threshold, goal) {f = g + heuristic(node, goal)if f > threshold return fif node == goal return FOUNDmin = ∞for each neighbor of node {temp = DFS(neighbor, g + cost, threshold, goal)if temp == FOUND return FOUNDif temp < min min = temp}return min
}</pre></div></section><div class="controls"><button id="setStart">设置起点</button><button id="setEnd">设置终点</button><button id="startPathfinding">开始寻路</button><button id="addObstacle">添加障碍物</button><button id="clearObstacles">清除障碍物</button><button id="reset">重置网格</button><button id="stepMode">单步模式: 关闭</button></div><div class="canvas-container"><canvas id="gridCanvas" width="600" height="500"></canvas></div><div class="legend"><div class="legend-item"><div class="legend-color" style="background-color: #2ecc71;"></div><span>起点</span></div><div class="legend-item"><div class="legend-color" style="background-color: #e74c3c;"></div><span>终点</span></div><div class="legend-item"><div class="legend-color" style="background-color: #34495e;"></div><span>障碍物</span></div><div class="legend-item"><div class="legend-color" style="background-color: #3498db;"></div><span>已探索节点</span></div><div class="legend-item"><div class="legend-color" style="background-color: #f1c40f;"></div><span>当前迭代节点</span></div><div class="legend-item"><div class="legend-color" style="background-color: #9b59b6;"></div><span>最终路径</span></div></div><div class="status" id="status">准备就绪 - 请设置起点和终点</div><div class="performance"><h3>算法性能统计</h3><div class="performance-stats"><div class="stat"><div class="stat-label">已探索节点</div><div class="stat-value" id="exploredNodes">0</div></div><div class="stat"><div class="stat-label">路径长度</div><div class="stat-value" id="pathLength">0</div></div><div class="stat"><div class="stat-label">计算时间</div><div class="stat-value" id="computationTime">0ms</div></div><div class="stat"><div class="stat-label">迭代次数</div><div class="stat-value" id="iterationCount">0</div></div></div></div><footer><p>IDA*算法路径规划可视化 &copy; 2023 | 使用HTML5 Canvas和JavaScript实现</p></footer></div><script>// 网格和画布设置const canvas = document.getElementById('gridCanvas');const ctx = canvas.getContext('2d');const gridSize = 20; // 每个网格的大小const rows = Math.floor(canvas.height / gridSize);const cols = Math.floor(canvas.width / gridSize);// 网格状态let grid = [];let start = null;let end = null;let path = [];let isSettingStart = false;let isSettingEnd = false;let isAddingObstacle = false;let isPathfinding = false;let stepMode = false;let animationId = null;// 算法状态let exploredNodes = 0;let computationStartTime = 0;let iterationCount = 0;let currentThreshold = 0;let currentPath = [];let visitedInCurrentIteration = [];// 初始化网格function initializeGrid() {grid = [];path = [];exploredNodes = 0;iterationCount = 0;currentThreshold = 0;currentPath = [];visitedInCurrentIteration = [];for (let i = 0; i < rows; i++) {grid[i] = [];for (let j = 0; j < cols; j++) {grid[i][j] = 0; // 0表示可通行,1表示障碍物}}drawGrid();updateStatus("网格已初始化");updatePerformanceStats();}// 绘制网格function drawGrid() {ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制网格线ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';ctx.lineWidth = 1;for (let i = 0; i <= rows; i++) {ctx.beginPath();ctx.moveTo(0, i * gridSize);ctx.lineTo(canvas.width, i * gridSize);ctx.stroke();}for (let j = 0; j <= cols; j++) {ctx.beginPath();ctx.moveTo(j * gridSize, 0);ctx.lineTo(j * gridSize, canvas.height);ctx.stroke();}// 绘制障碍物for (let i = 0; i < rows; i++) {for (let j = 0; j < cols; j++) {if (grid[i][j] === 1) {ctx.fillStyle = '#34495e';ctx.fillRect(j * gridSize, i * gridSize, gridSize, gridSize);}}}// 绘制已探索节点(当前迭代)for (const node of visitedInCurrentIteration) {ctx.fillStyle = 'rgba(52, 152, 219, 0.5)';ctx.fillRect(node.col * gridSize, node.row * gridSize, gridSize, gridSize);}// 绘制当前路径if (currentPath.length > 0) {ctx.strokeStyle = '#f1c40f';ctx.lineWidth = 2;ctx.beginPath();ctx.moveTo(currentPath[0].col * gridSize + gridSize / 2,currentPath[0].row * gridSize + gridSize / 2);for (let i = 1; i < currentPath.length; i++) {ctx.lineTo(currentPath[i].col * gridSize + gridSize / 2,currentPath[i].row * gridSize + gridSize / 2);}ctx.stroke();// 绘制当前路径节点for (const node of currentPath) {ctx.fillStyle = '#f1c40f';ctx.beginPath();ctx.arc(node.col * gridSize + gridSize / 2,node.row * gridSize + gridSize / 2,3, 0, Math.PI * 2);ctx.fill();}}// 绘制起点和终点if (start) {ctx.fillStyle = '#2ecc71';ctx.fillRect(start.col * gridSize, start.row * gridSize, gridSize, gridSize);}if (end) {ctx.fillStyle = '#e74c3c';ctx.fillRect(end.col * gridSize, end.row * gridSize, gridSize, gridSize);}// 绘制最终路径if (path.length > 0) {ctx.strokeStyle = '#9b59b6';ctx.lineWidth = 3;ctx.beginPath();ctx.moveTo(path[0].col * gridSize + gridSize / 2,path[0].row * gridSize + gridSize / 2);for (let i = 1; i < path.length; i++) {ctx.lineTo(path[i].col * gridSize + gridSize / 2,path[i].row * gridSize + gridSize / 2);}ctx.stroke();// 绘制最终路径节点for (const node of path) {ctx.fillStyle = '#9b59b6';ctx.beginPath();ctx.arc(node.col * gridSize + gridSize / 2,node.row * gridSize + gridSize / 2,4, 0, Math.PI * 2);ctx.fill();}}}// 更新状态显示function updateStatus(message) {document.getElementById('status').textContent = message;}// 更新性能统计function updatePerformanceStats() {document.getElementById('exploredNodes').textContent = exploredNodes;document.getElementById('pathLength').textContent = path.length > 0 ? path.length - 1 : 0;document.getElementById('iterationCount').textContent = iterationCount;if (computationStartTime > 0) {const computationTime = Date.now() - computationStartTime;document.getElementById('computationTime').textContent = computationTime + 'ms';}}// 计算两点之间的曼哈顿距离function manhattanDistance(node1, node2) {return Math.abs(node1.row - node2.row) + Math.abs(node1.col - node2.col);}// 获取邻居节点function getNeighbors(node) {const neighbors = [];const directions = [{ row: -1, col: 0 },  // 上{ row: 1, col: 0 },   // 下{ row: 0, col: -1 },  // 左{ row: 0, col: 1 },   // 右];for (const dir of directions) {const newRow = node.row + dir.row;const newCol = node.col + dir.col;if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && grid[newRow][newCol] === 0) {neighbors.push({ row: newRow, col: newCol });}}return neighbors;}// 深度受限搜索(IDA*核心)function depthLimitedSearch(node, g, threshold) {const f = g + manhattanDistance(node, end);// 超过阈值,返回f值用于下一轮迭代if (f > threshold) {return { found: false, nextThreshold: f };}// 找到目标if (node.row === end.row && node.col === end.col) {path = [...currentPath, node];return { found: true, nextThreshold: threshold };}exploredNodes++;visitedInCurrentIteration.push(node);let minNextThreshold = Infinity;// 获取邻居节点并排序(按启发式值)const neighbors = getNeighbors(node);neighbors.sort((a, b) => {return (g + 1 + manhattanDistance(a, end)) - (g + 1 + manhattanDistance(b, end));});for (const neighbor of neighbors) {// 避免循环if (currentPath.some(n => n.row === neighbor.row && n.col === neighbor.col)) {continue;}currentPath.push(neighbor);const result = depthLimitedSearch(neighbor, g + 1, threshold);currentPath.pop();if (result.found) {return result;}minNextThreshold = Math.min(minNextThreshold, result.nextThreshold);}return { found: false, nextThreshold: minNextThreshold };}// IDA*主算法function idaStar() {if (!start || !end) {updateStatus("请先设置起点和终点");return;}isPathfinding = true;computationStartTime = Date.now();exploredNodes = 0;iterationCount = 0;path = [];// 初始阈值currentThreshold = manhattanDistance(start, end);currentPath = [start];visitedInCurrentIteration = [start];updateStatus("开始IDA*寻路...");function iterate() {iterationCount++;visitedInCurrentIteration = [];const result = depthLimitedSearch(start, 0, currentThreshold);drawGrid();updatePerformanceStats();if (result.found) {updateStatus(`路径找到!长度: ${path.length - 1}`);isPathfinding = false;computationStartTime = 0;return;}if (result.nextThreshold === Infinity) {updateStatus("无法找到路径");isPathfinding = false;computationStartTime = 0;return;}// 更新阈值进行下一轮迭代currentThreshold = result.nextThreshold;currentPath = [start];if (stepMode) {updateStatus(`迭代 ${iterationCount} 完成,新阈值: ${currentThreshold},点击继续`);isPathfinding = false;} else {// 继续下一轮迭代setTimeout(iterate, 100);}}iterate();}// 事件监听canvas.addEventListener('click', function(event) {if (isPathfinding) return;const rect = canvas.getBoundingClientRect();const x = event.clientX - rect.left;const y = event.clientY - rect.top;const col = Math.floor(x / gridSize);const row = Math.floor(y / gridSize);if (row >= 0 && row < rows && col >= 0 && col < cols) {if (isSettingStart) {if (grid[row][col] === 0) {start = { row, col };isSettingStart = false;updateStatus("起点已设置");drawGrid();}} else if (isSettingEnd) {if (grid[row][col] === 0) {end = { row, col };isSettingEnd = false;updateStatus("终点已设置");drawGrid();}} else if (isAddingObstacle) {if ((!start || start.row !== row || start.col !== col) && (!end || end.row !== row || end.col !== col)) {grid[row][col] = 1;drawGrid();}} else {// 切换障碍物if ((!start || start.row !== row || start.col !== col) && (!end || end.row !== row || end.col !== col)) {grid[row][col] = grid[row][col] === 0 ? 1 : 0;drawGrid();}}}});document.getElementById('setStart').addEventListener('click', function() {isSettingStart = true;isSettingEnd = false;isAddingObstacle = false;updateStatus("请点击网格设置起点");});document.getElementById('setEnd').addEventListener('click', function() {isSettingEnd = true;isSettingStart = false;isAddingObstacle = false;updateStatus("请点击网格设置终点");});document.getElementById('startPathfinding').addEventListener('click', function() {if (!isPathfinding) {idaStar();} else if (stepMode && !isPathfinding) {// 单步模式下继续执行idaStar();}});document.getElementById('addObstacle').addEventListener('click', function() {isAddingObstacle = true;isSettingStart = false;isSettingEnd = false;updateStatus("请点击网格添加障碍物");});document.getElementById('clearObstacles').addEventListener('click', function() {for (let i = 0; i < rows; i++) {for (let j = 0; j < cols; j++) {if (grid[i][j] === 1) {grid[i][j] = 0;}}}drawGrid();updateStatus("障碍物已清除");});document.getElementById('reset').addEventListener('click', function() {start = null;end = null;initializeGrid();isPathfinding = false;updateStatus("网格已重置");});document.getElementById('stepMode').addEventListener('click', function() {stepMode = !stepMode;this.textContent = `单步模式: ${stepMode ? '开启' : '关闭'}`;updateStatus(`单步模式${stepMode ? '已开启' : '已关闭'}`);});// 初始化initializeGrid();</script>
</body>
</html>

功能说明

  1. 网格操作

    • 点击"设置起点"后点击网格设置起点(绿色)
    • 点击"设置终点"后点击网格设置终点(红色)
    • 点击"添加障碍物"后点击网格添加障碍物(黑色)
    • 直接点击网格可切换障碍物状态
    • 点击"清除障碍物"移除所有障碍物
  2. 算法控制

    • 点击"开始寻路"运行IDA*算法
    • 使用"单步模式"可以逐步观察算法迭代过程
  3. 可视化元素

    • 起点(绿色)和终点(红色)
    • 障碍物(黑色)
    • 当前迭代探索的节点(蓝色半透明)
    • 当前迭代的路径(黄色)
    • 最终路径(紫色)
  4. 性能统计

    • 已探索节点数
    • 路径长度
    • 计算时间
    • 迭代次数

IDA*算法特点

  • 通过逐步增加f值限制来寻找最优路径
  • 内存效率高,只存储当前路径
  • 适用于静态环境路径规划
  • 在每次迭代中探索f值不超过当前阈值的节点

可以直接复制上面的代码到HTML文件中运行,即可体验IDA*算法的可视化寻路过程。

http://www.dtcms.com/a/602244.html

相关文章:

  • 做境外网站临汾住房与城乡建设厅网站
  • 淘宝做链接的网站广告营销专业
  • 【网络编程基础知识】
  • js中哪些数据在栈上,哪些数据在堆上?
  • 上海云盾sdk游戏盾对比传统高防ip的优势
  • 系统配置重复项处理:经验未必可靠
  • 网站开发与应用 大作业作业辽宁省建设培训中心网站
  • 服务器与普通个人电脑的主要区别是什么?
  • 亚购物车功能网站怎么做的百度软件应用市场
  • 二项分布(Binomial Distribution)详解:从理论到实践
  • 深圳有没有什么网站重庆顶呱呱网站建设
  • 国外网站 设计成都注册公司核名网站
  • 衡阳网站建设开发价格谷歌推广新手教程
  • 【2025最新】05 Spring Security 构建 RESTful Web 注册服务
  • 基于java的无人驾驶物流配送与管理系统设计
  • 基于安卓的在线教育系统的设计与实现【附源码】
  • 河南网站seo地址深圳带停机坪的别墅
  • 专业做家具的网站swf上传wordpress
  • 硬件学习笔记--90 同步通信、异步通信、串行通信、并行通信介绍
  • linux练习1112-2
  • 力扣59 螺旋矩阵II java实现
  • 做网站内容需要自己填的建筑网校排行榜
  • 做推送好用的网站qq音乐怎么做mp3下载网站
  • 做家教有什么好的资料网站阜蒙县自治区建设学校网站
  • 无人机遥控接收机技术要点与难点
  • .NET高性能内存管理
  • [Powershell入门教程]第4天:模块、脚本编写、错误处理与 .NET 集成
  • 哈尔滨模板建站软件asp flash网站模板
  • 江阴公司网站建设河北网络营销推广seo
  • C#9、默认访问修饰符