Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 206 additions & 0 deletions GraphX.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import java.util.*;

final class NodeKey {
private final int[] coords;
private final int hash;

NodeKey(int... coords) {
this.coords = coords;
this.hash = Arrays.hashCode(coords);
}

@Override
public int hashCode() {
return hash;
}

@Override
public boolean equals(Object o) {
if (!(o instanceof NodeKey)) return false;
return Arrays.equals(coords, ((NodeKey) o).coords);
}
}

final class NodeIndexer {
private final Map<NodeKey, Integer> map = new HashMap<>();

int getOrCreate(int... coords) {
return map.computeIfAbsent(new NodeKey(coords), k -> map.size());
}

Integer get(int... coords) {
return map.get(new NodeKey(coords));
}

int size() {
return map.size();
}
}

class Graph {
static class Edge {
final int to;
final long w;

Edge(int t, long w) {
this.to = t;
this.w = w;
}
}

private final boolean directed;
private final NodeIndexer indexer = new NodeIndexer();
private final List<List<Edge>> adj = new ArrayList<>();

public Graph(boolean directed) {
this.directed = directed;
}

private void ensure(int u) {
while (adj.size() <= u) adj.add(new ArrayList<>());
}

public void addEdge(int from, int to, int w) {
addEdge(new int[] {from}, new int[] {to}, w);
}

public void addEdge(int[] from, int[] to, long w) {
int u = indexer.getOrCreate(from);
int v = indexer.getOrCreate(to);

ensure(u);
ensure(v);

adj.get(u).add(new Edge(v, w));
if (!directed) adj.get(v).add(new Edge(u, w));
}

public void addEdge(int[] from, int[] to) {
addEdge(from, to, 0);
}

public void addEdge(int from, int to) {
addEdge(from, to, 0);
}

int idOf(int... node) {
Integer id = indexer.get(node);
if (id == null) throw new IllegalArgumentException("Node not present");
return id;
}

int size() {
return indexer.size();
}

List<Edge> edges(int u) {
return adj.get(u);
}
}

class Dijkstra {
private final Graph g;
private long[] dist;
private boolean[] visited;

public Dijkstra(Graph g) {
this.g = g;
}

public void run(int... source) {
int s = g.idOf(source);
int n = g.size();

dist = new long[n];
visited = new boolean[n];
Arrays.fill(dist, Long.MAX_VALUE);

PriorityQueue<long[]> pq = new PriorityQueue<>(Comparator.comparingLong(a -> a[1]));
dist[s] = 0;
pq.add(new long[] {s, 0});

while (!pq.isEmpty()) {
long[] cur = pq.poll();
int u = (int) cur[0];

if (visited[u]) continue;
visited[u] = true;

for (Graph.Edge e : g.edges(u)) {
if (!visited[e.to] && dist[u] + e.w < dist[e.to]) {
dist[e.to] = dist[u] + e.w;
pq.add(new long[] {e.to, dist[e.to]});
}
}
}
}

public long minDist(int... target) {
return dist[g.idOf(target)];
}
}

class BFS {
private final Graph g;
private int[] dist;

public BFS(Graph g) {
this.g = g;
}

public void run(int... source) {
int s = g.idOf(source);
int n = g.size();

dist = new int[n];
Arrays.fill(dist, -1);

ArrayDeque<Integer> q = new ArrayDeque<>();
q.add(s);
dist[s] = 0;

while (!q.isEmpty()) {
int u = q.poll();
for (Graph.Edge e : g.edges(u)) {
if (dist[e.to] == -1) {
dist[e.to] = dist[u] + 1;
q.add(e.to);
}
}
}
}

public int minDist(int... target) {
return dist[g.idOf(target)];
}
}

public class GraphXBetter {
public static void main(String[] args) {
Graph g = new Graph(true);

// Add weighted edges
g.addEdge(1, 2, 5);
g.addEdge(1, 3, 3);
g.addEdge(2, 4, 6);
g.addEdge(3, 4, 2);
g.addEdge(4, 5, 8);

// Run BFS from node 1
BFS bfs = new BFS(g);
bfs.run(1);
System.out.println("BFS Distance from 1 to 5: " + bfs.minDist(5));

// Run Dijkstra from node 1
Dijkstra dijkstra = new Dijkstra(g);
dijkstra.run(1);
System.out.println("Dijkstra Distance from 1 to 5: " + dijkstra.minDist(5));

// Example with tuple-like nodes (using coordinates)
g.addEdge(new int[] {0, 0}, new int[] {0, 1}, 10);
g.addEdge(new int[] {0, 1}, new int[] {1, 1}, 15);

dijkstra.run(0, 0);
System.out.println("Distance to (1,1): " + dijkstra.minDist(1, 1));
}
}
160 changes: 160 additions & 0 deletions GraphX.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import heapq
from collections import deque


class NodeIndexer:
__slots__ = ("map",)

def __init__(self):
self.map = {}

def get_or_create(self, key):
idx = self.map.get(key)
if idx is None:
idx = len(self.map)
self.map[key] = idx
return idx

def get(self, key):
return self.map.get(key)

def size(self):
return len(self.map)


class Graph:
__slots__ = ("directed", "indexer", "adj")

def __init__(self, directed=True):
self.directed = directed
self.indexer = NodeIndexer()
self.adj = []

def _ensure(self, u):
if u >= len(self.adj):
self.adj.extend([] for _ in range(u + 1 - len(self.adj)))

def add_edge(self, u, v, w=0):
# normalize nodes → tuple
if not isinstance(u, tuple):
u = (u,)
if not isinstance(v, tuple):
v = (v,)

ui = self.indexer.get_or_create(u)
vi = self.indexer.get_or_create(v)

self._ensure(ui)
self._ensure(vi)

self.adj[ui].append((vi, w))
if not self.directed:
self.adj[vi].append((ui, w))

def id_of(self, node):
if not isinstance(node, tuple):
node = (node,)
idx = self.indexer.get(node)
if idx is None:
raise ValueError("Node not present")
return idx

def size(self):
return self.indexer.size()


class BFS:
__slots__ = ("g", "dist")

def __init__(self, g):
self.g = g
self.dist = []

def run(self, source):
if not isinstance(source, tuple):
source = (source,)
s = self.g.id_of(source)
n = self.g.size()

dist = [-1] * n
dist[s] = 0
q = deque([s])

while q:
u = q.popleft()
for v, _ in self.g.adj[u]:
if dist[v] == -1:
dist[v] = dist[u] + 1
q.append(v)

self.dist = dist

def min_dist(self, target):
if not isinstance(target, tuple):
target = (target,)
return self.dist[self.g.id_of(target)]


class Dijkstra:
__slots__ = ("g", "dist")

def __init__(self, g):
self.g = g
self.dist = []

def run(self, source):
if not isinstance(source, tuple):
source = (source,)
s = self.g.id_of(source)
n = self.g.size()

dist = [float("inf")] * n
dist[s] = 0
pq = [(0, s)]

while pq:
d, u = heapq.heappop(pq)

if d != dist[u]:
continue

for v, w in self.g.adj[u]:
nd = d + w
if nd < dist[v]:
dist[v] = nd
heapq.heappush(pq, (nd, v))

self.dist = dist

def min_dist(self, target):
if not isinstance(target, tuple):
target = (target,)
return self.dist[self.g.id_of(target)]


# ======================
# Example
# ======================

if __name__ == "__main__":
g = Graph(directed=True)

g.add_edge(1, 2, 5)
g.add_edge(1, 3, 3)
g.add_edge(2, 4, 6)
g.add_edge(3, 4, 2)
g.add_edge(4, 5, 8)

bfs = BFS(g)
bfs.run(1)
print("BFS 1 → 5:", bfs.min_dist(5))

d = Dijkstra(g)
d.run(1)
print("Dijkstra 1 → 5:", d.min_dist(5))

g.add_edge((0, 0), (0, 1), 10)
g.add_edge((0, 1), (1, 1), 15)

d.run((0, 0))
print("Distance to (1,1):", d.min_dist((1, 1)))