@@ -302,3 +302,135 @@ static PyObject* minimum_spanning_tree_prim_adjacency_list(PyObject* self, PyObj
302302 }
303303 return reinterpret_cast <PyObject*>(mst);
304304}
305+
306+ static PyObject* shortest_paths_dijkstra_adjacency_list (PyObject* self, PyObject* args, PyObject* kwargs) {
307+ PyObject* graph_obj;
308+ const char * source_name;
309+ const char * target_name = " " ;
310+
311+ static const char * kwlist[] = {" graph" , " source_node" , " target_node" , nullptr };
312+ if (!PyArg_ParseTupleAndKeywords (args, kwargs, " O!s|s" , const_cast <char **>(kwlist),
313+ &AdjacencyListGraphType, &graph_obj,
314+ &source_name, &target_name)) {
315+ return nullptr ;
316+ }
317+
318+ AdjacencyListGraph* graph = reinterpret_cast <AdjacencyListGraph*>(graph_obj);
319+
320+ const size_t V = graph->node_map .size ();
321+
322+ std::unordered_map<std::string, double > dist;
323+ std::unordered_map<std::string, std::string> pred;
324+
325+ for (const auto & [name, node] : graph->node_map ) {
326+ dist[name] = std::numeric_limits<double >::infinity ();
327+ pred[name] = " " ;
328+ }
329+ dist[source_name] = 0.0 ;
330+
331+ using PQEntry = std::pair<double , std::string>;
332+ std::priority_queue<PQEntry, std::vector<PQEntry>, std::greater<>> pq;
333+ pq.push ({0.0 , source_name});
334+
335+ while (!pq.empty ()) {
336+ auto [u_dist, u_name] = pq.top (); pq.pop ();
337+
338+ if (u_dist > dist[u_name]) continue ;
339+
340+ AdjacencyListGraphNode* u = graph->node_map [u_name];
341+ for (const auto & [v_name, _] : u->adjacent ) {
342+ std::string edge_key = make_edge_key (u_name, v_name);
343+ auto edge_it = graph->edges .find (edge_key);
344+ if (edge_it == graph->edges .end ()) continue ;
345+
346+ GraphEdge* edge = edge_it->second ;
347+ double weight = 0.0 ;
348+ if (edge->value_type == DataType::Int)
349+ weight = static_cast <double >(std::get<int64_t >(edge->value ));
350+ else if (edge->value_type == DataType::Double)
351+ weight = std::get<double >(edge->value );
352+ else
353+ continue ;
354+
355+ if (weight < 0 ) continue ;
356+
357+ double new_dist = dist[u_name] + weight;
358+ if (new_dist < dist[v_name]) {
359+ dist[v_name] = new_dist;
360+ pred[v_name] = u_name;
361+ pq.push ({new_dist, v_name});
362+ }
363+ }
364+ }
365+
366+ PyObject* dist_dict = PyDict_New ();
367+ PyObject* pred_dict = PyDict_New ();
368+ if (!dist_dict || !pred_dict) return nullptr ;
369+
370+ for (const auto & [v, d] : dist) {
371+ PyObject* dval = PyFloat_FromDouble (d);
372+ if (!dval || PyDict_SetItemString (dist_dict, v.c_str (), dval) < 0 ) {
373+ Py_XDECREF (dval);
374+ Py_DECREF (dist_dict);
375+ Py_DECREF (pred_dict);
376+ return nullptr ;
377+ }
378+ Py_DECREF (dval);
379+ }
380+
381+ for (const auto & [v, p] : pred) {
382+ PyObject* py_pred;
383+ if (p.empty ()) {
384+ Py_INCREF (Py_None);
385+ py_pred = Py_None;
386+ } else {
387+ py_pred = PyUnicode_FromString (p.c_str ());
388+ if (!py_pred) {
389+ Py_DECREF (dist_dict);
390+ Py_DECREF (pred_dict);
391+ return nullptr ;
392+ }
393+ }
394+
395+ if (PyDict_SetItemString (pred_dict, v.c_str (), py_pred) < 0 ) {
396+ Py_DECREF (py_pred);
397+ Py_DECREF (dist_dict);
398+ Py_DECREF (pred_dict);
399+ return nullptr ;
400+ }
401+ Py_DECREF (py_pred);
402+ }
403+
404+ if (strlen (target_name) > 0 ) {
405+ PyObject* out = PyTuple_New (2 );
406+ if (!out) {
407+ Py_DECREF (dist_dict);
408+ Py_DECREF (pred_dict);
409+ return nullptr ;
410+ }
411+
412+ PyObject* dist_val = PyFloat_FromDouble (dist[target_name]);
413+ if (!dist_val) {
414+ Py_DECREF (out);
415+ Py_DECREF (dist_dict);
416+ Py_DECREF (pred_dict);
417+ return nullptr ;
418+ }
419+
420+ PyTuple_SetItem (out, 0 , dist_val);
421+ PyTuple_SetItem (out, 1 , pred_dict);
422+ Py_DECREF (dist_dict);
423+ return out;
424+ }
425+
426+ PyObject* result = PyTuple_New (2 );
427+ if (!result) {
428+ Py_DECREF (dist_dict);
429+ Py_DECREF (pred_dict);
430+ return nullptr ;
431+ }
432+
433+ PyTuple_SetItem (result, 0 , dist_dict);
434+ PyTuple_SetItem (result, 1 , pred_dict);
435+ return result;
436+ }
0 commit comments