diff --git a/Graphs/Astar.js b/Graphs/Astar.js new file mode 100644 index 0000000000..fc20f6e79b --- /dev/null +++ b/Graphs/Astar.js @@ -0,0 +1,207 @@ +/** + * @author : Mathang Peddi + * A* Algorithm calculates the minimum cost path between two nodes. + * It is used to find the shortest path using heuristics. + * It uses graph data structure. + */ + +// Euclidean distance heuristic for 2D points +function euclideanHeuristic(pointA, pointB) { + const dx = pointA[0] - pointB[0] + const dy = pointA[1] - pointB[1] + return Math.sqrt(dx * dx + dy * dy) +} + +// Priority Queue (Min-Heap) implementation +class PriorityQueue { + constructor() { + this.elements = [] + } + + enqueue(node, priority) { + this.elements.push({ node, priority }) + this.bubbleUp() + } + + bubbleUp() { + let index = this.elements.length - 1 + while (index > 0) { + let parentIndex = Math.floor((index - 1) / 2) + if (this.elements[index].priority >= this.elements[parentIndex].priority) + break + ;[this.elements[index], this.elements[parentIndex]] = [ + this.elements[parentIndex], + this.elements[index] + ] + index = parentIndex + } + } + + dequeue() { + if (this.elements.length === 1) { + return this.elements.pop().node + } + + const node = this.elements[0].node + this.elements[0] = this.elements.pop() + this.sinkDown(0) + return node + } + + sinkDown(index) { + const length = this.elements.length + const element = this.elements[index] + while (true) { + let leftChildIndex = 2 * index + 1 + let rightChildIndex = 2 * index + 2 + let swapIndex = null + + if ( + leftChildIndex < length && + this.elements[leftChildIndex].priority < element.priority + ) { + swapIndex = leftChildIndex + } + + if ( + rightChildIndex < length && + this.elements[rightChildIndex].priority < + (swapIndex === null + ? element.priority + : this.elements[leftChildIndex].priority) + ) { + swapIndex = rightChildIndex + } + + if (swapIndex === null) break + ;[this.elements[index], this.elements[swapIndex]] = [ + this.elements[swapIndex], + this.elements[index] + ] + index = swapIndex + } + } + + isEmpty() { + return this.elements.length === 0 + } +} + +function aStar(graph, src, target, points) { + const openSet = new PriorityQueue() // Priority queue to explore nodes + openSet.enqueue(src, 0) + + const cameFrom = Array(graph.length).fill(null) // Keep track of path + const gScore = Array(graph.length).fill(Infinity) // Actual cost from start to a node + gScore[src] = 0 + + const fScore = Array(graph.length).fill(Infinity) // Estimated cost from start to goal (g + h) + fScore[src] = euclideanHeuristic(points[src], points[target]) + + while (!openSet.isEmpty()) { + // Get the node in openSet with the lowest fScore + const current = openSet.dequeue() + + // If the current node is the target, reconstruct the path and return + if (current === target) { + const path = [] + while (cameFrom[current] !== -1) { + path.push(current) + current = cameFrom[current] + } + path.push(src) + return path.reverse() + } + + // Explore neighbors using destructuring for cleaner code + for (const [neighbor, weight] of graph[current]) { + const tentative_gScore = gScore[current] + weight + + if (tentative_gScore < gScore[neighbor]) { + cameFrom[neighbor] = current + gScore[neighbor] = tentative_gScore + const priority = + gScore[neighbor] + + euclideanHeuristic(points[neighbor], points[target]) + fScore[neighbor] = priority + + openSet.enqueue(neighbor, priority) + } + } + } + + return null // Return null if there's no path to the target +} + +// Define the graph as an adjacency list +const graph = [ + [ + [1, 4], + [7, 8] + ], // Node 0 connects to node 1 (weight 4), node 7 (weight 8) + [ + [0, 4], + [2, 8], + [7, 11] + ], // Node 1 connects to node 0, node 2, node 7 + [ + [1, 8], + [3, 7], + [5, 4], + [8, 2] + ], // Node 2 connects to several nodes + [ + [2, 7], + [4, 9], + [5, 14] + ], // Node 3 connects to nodes 2, 4, 5 + [ + [3, 9], + [5, 10] + ], // Node 4 connects to nodes 3 and 5 + [ + [2, 4], + [3, 14], + [4, 10], + [6, 2] + ], // Node 5 connects to several nodes + [ + [5, 2], + [7, 1], + [8, 6] + ], // Node 6 connects to nodes 5, 7, 8 + [ + [0, 8], + [1, 11], + [6, 1], + [8, 7] + ], // Node 7 connects to several nodes + [ + [2, 2], + [6, 6], + [7, 7] + ] // Node 8 connects to nodes 2, 6, 7 +] + +// Define 2D coordinates for each node (these can be changed based on actual node positions) +const points = [ + [0, 0], // Point for node 0 + [1, 2], // Point for node 1 + [2, 1], // Point for node 2 + [3, 5], // Point for node 3 + [4, 3], // Point for node 4 + [5, 6], // Point for node 5 + [6, 8], // Point for node 6 + [7, 10], // Point for node 7 + [8, 12] // Point for node 8 +] + +// Call the aStar function with the graph, source node (0), and target node (4) +const path = aStar(graph, 0, 4, points) + +console.log('Shortest path from node 0 to node 4:', path) + +/** + * The function returns the optimal path from the source to the target node. + * The heuristic used is Euclidean distance between nodes' 2D coordinates. + */ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy