Dsa Report
Dsa Report
COLLEGE OF ENGINEERING
(Autonomous college under VTU)
Bull Temple Rd, Basavanagudi, Bengaluru, Karnataka
2023-2024
Department of Computer Applications
Report is submitted for fulfillment of AAT work in the subject
By
BHASKAR S(1BM23MC021)
MANOHAR T H(1BM23MC051)
T S Pushpa
(Assistant Professor)
CONTENTS
SL. Page
No. Programs No.
1. Problem Statement
Source Code
3.
Conclusion
7.
Reference
9.
22MCA2PCDS: Data Structures and Algorithms
1. Problem Statement
Implement the Best First Search algorithm to find the shortest path between a
given start node and a goal node in a graph. The algorithm should account for
different possible paths, select the most efficient one based on a cost function, and
ensure optimal performance in terms of both time and space.
Design an BEST FIRST SEARCH algorithm to find the shortest path between two
nodes in a weighted, undirected graph. The algorithm should account for both the
cost to reach a node (g_score) and an estimated cost to reach the goal (heuristic
h_score). Visualize the graph, highlight the shortest paths, and provide details
about total path costs.
The graph can represent any real-world scenario, such as navigating through a
map, where nodes represent points of interest, and edges represent the paths
between them with respective weights.
Design Technique
The Best First Search algorithm uses a Greedy Best-First Search combined with
Dijkstra's algorithm principles. It incorporates both the actual distance from the
start node (g_score) and a heuristic estimate (h_score) of the distance to the goal.
A* prioritizes nodes based on their total estimated cost (f_score = g_score +
h_score).
Key Steps:
1. Maintain an open set of nodes to be evaluated.
2. Track g_score for each node (cost to reach the node).
3. Use a priority heuristic (f_score = g_score + heuristic) to select nodes.
4. For each node, compute tentative scores and update paths.
5. Continue until the goal node is reached or the open set is empty.
3. Source Code
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
#define MAX_NODES 10
#define INFINITY INT_MAX
typedef struct {
char name; // Node name for output
int edges[MAX_NODES]; // Adjacency list
int edgeCount; // Number of edges
int cost[MAX_NODES]; // Costs for each edge
} Node;
Node graph[MAX_NODES];
bool openList[MAX_NODES];
bool closedList[MAX_NODES];
int gCost[MAX_NODES]; // Cost from start to node
int parent[MAX_NODES]; // Parent node for path reconstruction
int nodeCount = 0;
gCost[startIdx] = 0;
openList[startIdx] = true;
while (true) {
int minIndex = -1;
for (int i = 0; i < nodeCount; i++) {
if (openList[i] && (minIndex == -1 || gCost[i] < gCost[minIndex])) {
minIndex = i;
}
}
if (minIndex == -1) {
printf("No path found\n");
return;
}
if (minIndex == goalIdx) {
printf("Path found: ");
int current = goalIdx;
while (current != -1) {
printf("%c", graph[current].name);
if (parent[current] != -1) printf7("->");
current = parent[current];
}
printf(" = [%d]\n", gCost[goalIdx]);
return;
}
openList[minIndex] = false;
int main() {
// Setup graph
addNode('A'); // Node 0
addNode('B'); // Node 1
addNode('C'); // Node 2
addNode('D'); // Node 3
addNode('E'); // Node 4
aStar(startIdx, goalIdx);
return 0;
}
OUTPUT:
IN Python:
import heapq
class Graph:
def _init_(self):
self.edges = {}
self.h_weights = {}
while open_set:
_, current = heapq.heappop(open_set)
if current == goal:
return self.reconstruct_path(came_from, current, g_score)
# Example Usage
graph = Graph()
graph.set_heuristic('C', 3)
graph.set_heuristic('D', 2)
graph.set_heuristic('E', 1)
graph.set_heuristic('F', 0)
In java
import java.util.*;
Node(String name) {
this.name = name;
edges = new HashMap<>();
}
@Override
public int compareTo(Node other) {
return Integer.compare(g + h, other.g + other.h);
}
}
class Graph {
Map<String, Node> nodes;
Graph() {
nodes = new HashMap<>();
}
class AStar {
static List<String> findShortestPath(Node start, Node goal) {
PriorityQueue<Node> open = new PriorityQueue<>();
Set<Node> closed = new HashSet<>();
start.g = 0;
start.h = heuristic(start, goal);
open.offer(start);
while (!open.isEmpty()) {
Node current = open.poll();
if (current == goal) {
return reconstructPath(current);
}
closed.add(current);
for (Map.Entry<Node, Integer> entry : current.edges.entrySet()) {
Node neighbor = entry.getKey();
int tentativeG = current.g + entry.getValue();
if (closed.contains(neighbor) && tentativeG >= neighbor.g) {
continue;
}
if (!open.contains(neighbor) || tentativeG < neighbor.g) {
neighbor.parent = current;
neighbor.g = tentativeG;
neighbor.h = heuristic(neighbor, goal);
if (!open.contains(neighbor)) {
open.offer(neighbor);
}
}
}
}
return null; // No path found
}
return pathsFromSource;
}
}
}
// Define nodes
String[] nodes = {"A", "B", "C", "D", "E", "F"};
// Find and print all shortest paths from the source node to all other nodes
System.out.println("\nShortest paths from " + sourceNode + " to all other
nodes:");
Map<String, String> shortestPathsFromSource =
Department of Computer Applications, BMSCE 12
22MCA2PCDS: Data Structures and Algorithms
AStar.findShortestPathsFromSource(graph, sourceNode);
for (Map.Entry<String, String> entry : shortestPathsFromSource.entrySet()) {
System.out.println("To " + entry.getKey() + ": " + entry.getValue());
}
}
}
OUTPUT:
Python Implementation:
Time Complexity: O(E + V log V)
Space Complexity: O(V)
C Implementation
Time Complexity: O(E + V log V)
Space Complexity: O(V)
Java Implementation:
Time Complexity: O(E + V log V)
Space Complexity: O(V)
6. Conclusion
The A* algorithm's performance varies significantly depending on the
programming language and the efficiency of the underlying data structures used.
In general:
Python is user-friendly and suitable for rapid prototyping but may face
performance bottlenecks due to its higher-level abstractions and memory
management. Utilizing a priority queue (like heapq) can improve time
complexity, but Python's inherent overhead still makes it slower compared to
lower-level languages.
Java provides a balance between performance and ease of use, with better
execution speed than Python and the benefit of a rich standard library.
However, it still incurs some overhead from the JVM, making it slower than
C++.
C delivers the most optimized solution for both time and space, as developers
have direct control over memory allocation and data structures. It is the go-to
choice for highly performance-sensitive applications where minimal overhead
is essential.
7. Reference