Skip to content

Commit 90eac72

Browse files
committed
Review changes
1 parent a9e17ed commit 90eac72

File tree

1 file changed

+140
-93
lines changed

1 file changed

+140
-93
lines changed

Graphs/Astar.js

Lines changed: 140 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,154 @@
11
/**
2-
* Author: Mathang Peddi
3-
* A* Search Algorithm implementation in JavaScript
2+
* @author Mathang Peddi
43
* A* Algorithm calculates the minimum cost path between two nodes.
54
* It is used to find the shortest path using heuristics.
65
* It uses graph data structure.
76
*/
87

9-
function createGraph(V, E) {
10-
// V - Number of vertices in graph
11-
// E - Number of edges in graph (u,v,w)
12-
const adjList = [] // Adjacency list
13-
for (let i = 0; i < V; i++) {
14-
adjList.push([])
8+
// Euclidean distance heuristic for 2D points
9+
function euclideanHeuristic(pointA, pointB) {
10+
const dx = pointA[0] - pointB[0];
11+
const dy = pointA[1] - pointB[1];
12+
return Math.sqrt(dx * dx + dy * dy);
1513
}
16-
for (let i = 0; i < E.length; i++) {
17-
adjList[E[i][0]].push([E[i][1], E[i][2]])
18-
adjList[E[i][1]].push([E[i][0], E[i][2]])
19-
}
20-
return adjList
21-
}
22-
23-
// Heuristic function to estimate the cost to reach the goal
24-
// You can modify this based on your specific problem, for now, we're using Manhattan distance
25-
function heuristic(a, b) {
26-
return Math.abs(a - b)
27-
}
28-
29-
function aStar(graph, V, src, target) {
30-
const openSet = new Set([src]) // Nodes to explore
31-
const cameFrom = Array(V).fill(-1) // Keep track of path
32-
const gScore = Array(V).fill(Infinity) // Actual cost from start to a node
33-
gScore[src] = 0
34-
35-
const fScore = Array(V).fill(Infinity) // Estimated cost from start to goal (g + h)
36-
fScore[src] = heuristic(src, target)
37-
38-
while (openSet.size > 0) {
39-
// Get the node in openSet with the lowest fScore
40-
let current = -1
41-
openSet.forEach((node) => {
42-
if (current === -1 || fScore[node] < fScore[current]) {
43-
current = node
14+
15+
// Priority Queue (Min-Heap) implementation
16+
class PriorityQueue {
17+
constructor() {
18+
this.elements = [];
19+
}
20+
21+
enqueue(node, priority) {
22+
this.elements.push({ node, priority });
23+
this.bubbleUp();
24+
}
25+
26+
bubbleUp() {
27+
let index = this.elements.length - 1;
28+
while (index > 0) {
29+
let parentIndex = Math.floor((index - 1) / 2);
30+
if (this.elements[index].priority >= this.elements[parentIndex].priority) break;
31+
[this.elements[index], this.elements[parentIndex]] = [this.elements[parentIndex], this.elements[index]];
32+
index = parentIndex;
4433
}
45-
})
46-
47-
// If the current node is the target, reconstruct the path and return
48-
if (current === target) {
49-
const path = []
50-
while (cameFrom[current] !== -1) {
51-
path.push(current)
52-
current = cameFrom[current]
34+
}
35+
36+
dequeue() {
37+
if (this.elements.length === 1) {
38+
return this.elements.pop().node;
5339
}
54-
path.push(src)
55-
return path.reverse()
40+
41+
const node = this.elements[0].node;
42+
this.elements[0] = this.elements.pop();
43+
this.sinkDown(0);
44+
return node;
5645
}
57-
58-
openSet.delete(current)
59-
60-
// Explore neighbors
61-
for (let i = 0; i < graph[current].length; i++) {
62-
const neighbor = graph[current][i][0]
63-
const tentative_gScore = gScore[current] + graph[current][i][1]
64-
65-
if (tentative_gScore < gScore[neighbor]) {
66-
cameFrom[neighbor] = current
67-
gScore[neighbor] = tentative_gScore
68-
fScore[neighbor] = gScore[neighbor] + heuristic(neighbor, target)
69-
70-
if (!openSet.has(neighbor)) {
71-
openSet.add(neighbor)
46+
47+
sinkDown(index) {
48+
const length = this.elements.length;
49+
const element = this.elements[index];
50+
while (true) {
51+
let leftChildIndex = 2 * index + 1;
52+
let rightChildIndex = 2 * index + 2;
53+
let swapIndex = null;
54+
55+
if (leftChildIndex < length && this.elements[leftChildIndex].priority < element.priority) {
56+
swapIndex = leftChildIndex;
57+
}
58+
59+
if (rightChildIndex < length && this.elements[rightChildIndex].priority < (swapIndex === null ? element.priority : this.elements[leftChildIndex].priority)) {
60+
swapIndex = rightChildIndex;
7261
}
62+
63+
if (swapIndex === null) break;
64+
65+
[this.elements[index], this.elements[swapIndex]] = [this.elements[swapIndex], this.elements[index]];
66+
index = swapIndex;
7367
}
7468
}
69+
70+
isEmpty() {
71+
return this.elements.length === 0;
72+
}
7573
}
76-
77-
return [] // Return empty path if there's no path to the target
78-
}
79-
80-
module.exports = { createGraph, aStar }
81-
82-
// const V = 9
83-
// const E = [
84-
// [0, 1, 4],
85-
// [0, 7, 8],
86-
// [1, 7, 11],
87-
// [1, 2, 8],
88-
// [7, 8, 7],
89-
// [6, 7, 1],
90-
// [2, 8, 2],
91-
// [6, 8, 6],
92-
// [5, 6, 2],
93-
// [2, 5, 4],
94-
// [2, 3, 7],
95-
// [3, 5, 14],
96-
// [3, 4, 9],
97-
// [4, 5, 10]
98-
// ]
99-
100-
// const graph = createGraph(V, E)
101-
// const path = aStar(graph, V, 0, 4) // Find path from node 0 to node 4
102-
// console.log(path)
103-
104-
/**
105-
* The function returns the optimal path from the source to the target node.
106-
* The heuristic used is Manhattan distance but it can be modified.
107-
*/
74+
75+
function aStar(graph, src, target, points) {
76+
const openSet = new PriorityQueue(); // Priority queue to explore nodes
77+
openSet.enqueue(src, 0);
78+
79+
const cameFrom = Array(graph.length).fill(null); // Keep track of path
80+
const gScore = Array(graph.length).fill(Infinity); // Actual cost from start to a node
81+
gScore[src] = 0;
82+
83+
const fScore = Array(graph.length).fill(Infinity); // Estimated cost from start to goal (g + h)
84+
fScore[src] = euclideanHeuristic(points[src], points[target]);
85+
86+
while (!openSet.isEmpty()) {
87+
// Get the node in openSet with the lowest fScore
88+
const current = openSet.dequeue();
89+
90+
// If the current node is the target, reconstruct the path and return
91+
if (current === target) {
92+
const path = [];
93+
while (cameFrom[current] !== -1) {
94+
path.push(current);
95+
current = cameFrom[current];
96+
}
97+
path.push(src);
98+
return path.reverse();
99+
}
100+
101+
// Explore neighbors using destructuring for cleaner code
102+
for (const [neighbor, weight] of graph[current]) {
103+
const tentative_gScore = gScore[current] + weight;
104+
105+
if (tentative_gScore < gScore[neighbor]) {
106+
cameFrom[neighbor] = current;
107+
gScore[neighbor] = tentative_gScore;
108+
const priority = gScore[neighbor] + euclideanHeuristic(points[neighbor], points[target]);
109+
fScore[neighbor] = priority;
110+
111+
openSet.enqueue(neighbor, priority);
112+
}
113+
}
114+
}
115+
116+
return null; // Return null if there's no path to the target
117+
}
118+
119+
// Define the graph as an adjacency list
120+
const graph = [
121+
[[1, 4], [7, 8]], // Node 0 connects to node 1 (weight 4), node 7 (weight 8)
122+
[[0, 4], [2, 8], [7, 11]], // Node 1 connects to node 0, node 2, node 7
123+
[[1, 8], [3, 7], [5, 4], [8, 2]], // Node 2 connects to several nodes
124+
[[2, 7], [4, 9], [5, 14]], // Node 3 connects to nodes 2, 4, 5
125+
[[3, 9], [5, 10]], // Node 4 connects to nodes 3 and 5
126+
[[2, 4], [3, 14], [4, 10], [6, 2]], // Node 5 connects to several nodes
127+
[[5, 2], [7, 1], [8, 6]], // Node 6 connects to nodes 5, 7, 8
128+
[[0, 8], [1, 11], [6, 1], [8, 7]], // Node 7 connects to several nodes
129+
[[2, 2], [6, 6], [7, 7]] // Node 8 connects to nodes 2, 6, 7
130+
];
131+
132+
// Define 2D coordinates for each node (these can be changed based on actual node positions)
133+
const points = [
134+
[0, 0], // Point for node 0
135+
[1, 2], // Point for node 1
136+
[2, 1], // Point for node 2
137+
[3, 5], // Point for node 3
138+
[4, 3], // Point for node 4
139+
[5, 6], // Point for node 5
140+
[6, 8], // Point for node 6
141+
[7, 10], // Point for node 7
142+
[8, 12] // Point for node 8
143+
];
144+
145+
// Call the aStar function with the graph, source node (0), and target node (4)
146+
const path = aStar(graph, 0, 4, points);
147+
148+
console.log('Shortest path from node 0 to node 4:', path);
149+
150+
/**
151+
* The function returns the optimal path from the source to the target node.
152+
* The heuristic used is Euclidean distance between nodes' 2D coordinates.
153+
*/
154+

0 commit comments

Comments
 (0)
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