@@ -18,6 +18,8 @@ namespace CXXGRAPH
18
18
constexpr char ERR_NO_DIR_OR_UNDIR_EDGE[] = " Edge are neither Directed neither Undirected" ;
19
19
constexpr char ERR_NO_WEIGHTED_EDGE[] = " Edge are not Weighted" ;
20
20
constexpr char ERR_DIJ_TARGET_NODE_NOT_REACHABLE[] = " Target Node not Reachable" ;
21
+ constexpr char ERR_DIJ_TARGET_NODE_NOT_IN_GRAPH[] = " Target Node not inside Graph" ;
22
+ constexpr char ERR_DIJ_SOURCE_NODE_NOT_IN_GRAPH[] = " Source Node not inside Graph" ;
21
23
// /////////////////////////////
22
24
constexpr double INF_DOUBLE = std::numeric_limits<double >::max();
23
25
template <typename T>
@@ -38,7 +40,7 @@ namespace CXXGRAPH
38
40
class Weighted ;
39
41
40
42
template <typename T>
41
- using AdjacencyMatrix = std::map<const Node<T>*, std::vector<std::pair<const Node<T>*, const Edge<T>*>>>;
43
+ using AdjacencyMatrix = std::map<const Node<T> *, std::vector<std::pair<const Node<T> *, const Edge<T> *>>>;
42
44
43
45
template <typename T>
44
46
std::ostream &operator <<(std::ostream &o, const Node<T> &node);
@@ -57,11 +59,12 @@ namespace CXXGRAPH
57
59
template <typename T>
58
60
std::ostream &operator <<(std::ostream &o, const AdjacencyMatrix<T> &adj);
59
61
60
- typedef struct DijkstraResult_struct {
61
- bool success; // TRUE if the function does not return error, FALSE otherwise
62
+ typedef struct DijkstraResult_struct
63
+ {
64
+ bool success; // TRUE if the function does not return error, FALSE otherwise
62
65
std::string errorMessage; // message of error
63
- double result; // result (valid only if success is TRUE)
64
- }DijkstraResult;
66
+ double result; // result (valid only if success is TRUE)
67
+ } DijkstraResult;
65
68
66
69
template <typename T>
67
70
class Node
@@ -456,7 +459,7 @@ namespace CXXGRAPH
456
459
{
457
460
private:
458
461
std::set<const Edge<T> *> edgeSet;
459
- void addElementToAdjMatrix (AdjacencyMatrix<T> &adjMatrix, const Node<T>* nodeFrom, const Node<T>* nodeTo, const Edge<T>* edge) const ;
462
+ void addElementToAdjMatrix (AdjacencyMatrix<T> &adjMatrix, const Node<T> * nodeFrom, const Node<T> * nodeTo, const Edge<T> * edge) const ;
460
463
461
464
public:
462
465
Graph () = default ;
@@ -466,6 +469,7 @@ namespace CXXGRAPH
466
469
void setEdgeSet (std::set<const Edge<T> *> &edgeSet);
467
470
void addEdge (const Edge<T> &edge);
468
471
void removeEdge (unsigned long edgeId);
472
+ const std::set<const Node<T> *> getNodeSet () const ;
469
473
const std::optional<const Edge<T> *> getEdge (unsigned long edgeId) const ;
470
474
/* This function generate a list of adjacency matrix with every element of the matrix
471
475
***contain the node where is directed the link and the Edge corrispondent to the link
@@ -483,6 +487,16 @@ namespace CXXGRAPH
483
487
* case if target is not reachable from source or there is error in the computation.
484
488
*/
485
489
const DijkstraResult dijkstra (const Node<T> &source, const Node<T> &target) const ;
490
+ /* *
491
+ * \brief
492
+ * Function performs the breadth first search algorithm over the graph
493
+ *
494
+ * @param start Node from where traversing starts
495
+ * @returns a vector of Node indicating which Node were visited during the
496
+ * search.
497
+ *
498
+ */
499
+ const std::vector<Node<T>> breadth_first_search (const Node<T> &start) const ;
486
500
487
501
friend std::ostream &operator <<<>(std::ostream &os, const Graph<T> &graph);
488
502
friend std::ostream &operator <<<>(std::ostream &os, const AdjacencyMatrix<T> &adj);
@@ -521,6 +535,17 @@ namespace CXXGRAPH
521
535
edgeSet.erase (edgeSet.find (edgeOpt.value ()));
522
536
}
523
537
}
538
+
539
+ template <typename T>
540
+ const std::set<const Node<T> *> Graph<T>::getNodeSet() const
541
+ {
542
+ std::set<const Node<T> *> nodeSet;
543
+ for (auto edge : edgeSet){
544
+ nodeSet.insert (edge->getNodePair ().first );
545
+ nodeSet.insert (edge->getNodePair ().second );
546
+ }
547
+ return nodeSet;
548
+ }
524
549
525
550
template <typename T>
526
551
const std::optional<const Edge<T> *> Graph<T>::getEdge(unsigned long edgeId) const
@@ -539,9 +564,9 @@ namespace CXXGRAPH
539
564
}
540
565
541
566
template <typename T>
542
- void Graph<T>::addElementToAdjMatrix(AdjacencyMatrix<T> &adjMatrix, const Node<T>* nodeFrom, const Node<T>* nodeTo, const Edge<T>* edge) const
567
+ void Graph<T>::addElementToAdjMatrix(AdjacencyMatrix<T> &adjMatrix, const Node<T> * nodeFrom, const Node<T> * nodeTo, const Edge<T> * edge) const
543
568
{
544
- std::pair<const Node<T>*, const Edge<T>*> elem = {nodeTo, edge};
569
+ std::pair<const Node<T> *, const Edge<T> *> elem = {nodeTo, edge};
545
570
adjMatrix[nodeFrom].push_back (elem);
546
571
547
572
// adjMatrix[nodeFrom.getId()].push_back(std::make_pair<const Node<T>,const Edge<T>>(nodeTo, edge));
@@ -556,12 +581,13 @@ namespace CXXGRAPH
556
581
{
557
582
if ((*edgeSetIt)->isDirected ().has_value () && (*edgeSetIt)->isDirected ().value ())
558
583
{
559
- const DirectedEdge<T>* d_edge = dynamic_cast <const DirectedEdge<T>*>(*edgeSetIt);
584
+ const DirectedEdge<T> * d_edge = dynamic_cast <const DirectedEdge<T> *>(*edgeSetIt);
560
585
addElementToAdjMatrix (adj, &(d_edge->getFrom ()), &(d_edge->getTo ()), d_edge);
561
586
}
562
587
else if ((*edgeSetIt)->isDirected ().has_value () && !(*edgeSetIt)->isDirected ().value ())
563
588
{
564
- const UndirectedEdge<T>* ud_edge = dynamic_cast <const UndirectedEdge<T>*>(*edgeSetIt);;
589
+ const UndirectedEdge<T> *ud_edge = dynamic_cast <const UndirectedEdge<T> *>(*edgeSetIt);
590
+ ;
565
591
addElementToAdjMatrix (adj, &(ud_edge->getNode1 ()), &(ud_edge->getNode2 ()), ud_edge);
566
592
addElementToAdjMatrix (adj, &(ud_edge->getNode2 ()), &(ud_edge->getNode1 ()), ud_edge);
567
593
}
@@ -580,12 +606,21 @@ namespace CXXGRAPH
580
606
result.success = false ;
581
607
result.errorMessage = " " ;
582
608
result.result = INF_DOUBLE;
609
+ auto nodeSet = getNodeSet ();
610
+ if (nodeSet.find (&source) == nodeSet.end ()){ // check if source node exist in the graph
611
+ result.errorMessage = ERR_DIJ_SOURCE_NODE_NOT_IN_GRAPH;
612
+ return result;
613
+ }
614
+ if (nodeSet.find (&target) == nodeSet.end ()){ // check if target node exist in the graph
615
+ result.errorMessage = ERR_DIJ_TARGET_NODE_NOT_IN_GRAPH;
616
+ return result;
617
+ }
583
618
const AdjacencyMatrix<T> adj = getAdjMatrix ();
584
619
// / n denotes the number of vertices in graph
585
620
int n = adj.size ();
586
621
587
622
// / setting all the distances initially to INF_DOUBLE
588
- std::map<const Node<T>*, double > dist;
623
+ std::map<const Node<T> *, double > dist;
589
624
590
625
for (auto elem : adj)
591
626
{
@@ -595,8 +630,8 @@ namespace CXXGRAPH
595
630
// / creating a min heap using priority queue
596
631
// / first element of pair contains the distance
597
632
// / second element of pair contains the vertex
598
- std::priority_queue<std::pair<double ,const Node<T>*>, std::vector<std::pair<double ,const Node<T>*>>,
599
- std::greater<std::pair<double ,const Node<T>*>>>
633
+ std::priority_queue<std::pair<double , const Node<T> *>, std::vector<std::pair<double , const Node<T> *>>,
634
+ std::greater<std::pair<double , const Node<T> *>>>
600
635
pq;
601
636
602
637
// / pushing the source vertex 's' with 0 distance in min heap
@@ -608,7 +643,7 @@ namespace CXXGRAPH
608
643
while (!pq.empty ())
609
644
{
610
645
// / second element of pair denotes the node / vertex
611
- const Node<T>* currentNode = pq.top ().second ;
646
+ const Node<T> * currentNode = pq.top ().second ;
612
647
613
648
// / first element of pair denotes the distance
614
649
double currentDist = pq.top ().first ;
@@ -617,36 +652,44 @@ namespace CXXGRAPH
617
652
618
653
// / for all the reachable vertex from the currently exploring vertex
619
654
// / we will try to minimize the distance
620
- for (std::pair< const Node<T>*, const Edge<T>*> elem : adj.at (currentNode ))
655
+ if (adj. find (currentNode) != adj.end ( ))
621
656
{
622
- // / minimizing distances
623
- if (elem.second ->isWeighted ().has_value () && elem.second ->isWeighted ().value ())
657
+ for (std::pair<const Node<T> *, const Edge<T> *> elem : adj.at (currentNode))
624
658
{
625
- if (elem.second ->isDirected ().has_value () && elem.second ->isDirected ().value ()){
626
- const DirectedWeightedEdge<T> *dw_edge = dynamic_cast <const DirectedWeightedEdge<T> *>(elem.second );
627
- if (currentDist +dw_edge->getWeight () < dist[elem.first ])
659
+ // / minimizing distances
660
+ if (elem.second ->isWeighted ().has_value () && elem.second ->isWeighted ().value ())
661
+ {
662
+ if (elem.second ->isDirected ().has_value () && elem.second ->isDirected ().value ())
628
663
{
629
- dist[elem.first ] = currentDist + dw_edge->getWeight ();
630
- pq.push (std::make_pair (dist[elem.first ], elem.first ));
664
+ const DirectedWeightedEdge<T> *dw_edge = dynamic_cast <const DirectedWeightedEdge<T> *>(elem.second );
665
+ if (currentDist + dw_edge->getWeight () < dist[elem.first ])
666
+ {
667
+ dist[elem.first ] = currentDist + dw_edge->getWeight ();
668
+ pq.push (std::make_pair (dist[elem.first ], elem.first ));
669
+ }
631
670
}
632
- }else if (elem.second ->isDirected ().has_value () && !elem.second ->isDirected ().value ()){
633
- const UndirectedWeightedEdge<T> *udw_edge = dynamic_cast <const UndirectedWeightedEdge<T> *>(elem.second );
634
- if (currentDist + udw_edge->getWeight () < dist[elem.first ])
671
+ else if (elem.second ->isDirected ().has_value () && !elem.second ->isDirected ().value ())
635
672
{
636
- dist[elem.first ] = currentDist + udw_edge->getWeight ();
637
- pq.push (std::make_pair (dist[elem.first ], elem.first ));
673
+ const UndirectedWeightedEdge<T> *udw_edge = dynamic_cast <const UndirectedWeightedEdge<T> *>(elem.second );
674
+ if (currentDist + udw_edge->getWeight () < dist[elem.first ])
675
+ {
676
+ dist[elem.first ] = currentDist + udw_edge->getWeight ();
677
+ pq.push (std::make_pair (dist[elem.first ], elem.first ));
678
+ }
638
679
}
639
- }else {
640
- // ERROR it shouldn't never returned ( does not exist a Node Weighted and not Directed/Undirected)
641
- result.errorMessage = ERR_NO_DIR_OR_UNDIR_EDGE;
680
+ else
681
+ {
682
+ // ERROR it shouldn't never returned ( does not exist a Node Weighted and not Directed/Undirected)
683
+ result.errorMessage = ERR_NO_DIR_OR_UNDIR_EDGE;
684
+ return result;
685
+ }
686
+ }
687
+ else
688
+ { // No Weighted Edge
689
+ result.errorMessage = ERR_NO_WEIGHTED_EDGE;
642
690
return result;
643
691
}
644
692
}
645
- else
646
- { // No Weighted Edge
647
- result.errorMessage = ERR_NO_WEIGHTED_EDGE;
648
- return result;
649
- }
650
693
}
651
694
}
652
695
if (dist[&target] != INF_DOUBLE)
@@ -660,7 +703,43 @@ namespace CXXGRAPH
660
703
result.result = -1 ;
661
704
return result;
662
705
}
663
-
706
+
707
+ template <typename T>
708
+ const std::vector<Node<T>> Graph<T>::breadth_first_search(const Node<T> &start) const
709
+ {
710
+ const AdjacencyMatrix<T> adj = getAdjMatrix ();
711
+ // / vector to keep track of visited nodes
712
+ std::vector<Node<T>> visited;
713
+ // / queue that stores vertices that need to be further explored
714
+ std::queue<const Node<T> *> tracker;
715
+ auto nodeSet = getNodeSet ();
716
+ if (nodeSet.find (&start) != nodeSet.end ()) // check is exist node in the graph
717
+ {
718
+ // / mark the starting node as visited
719
+ visited.push_back (start);
720
+ tracker.push (&start);
721
+ while (!tracker.empty ())
722
+ {
723
+ const Node<T> *node = tracker.front ();
724
+ tracker.pop ();
725
+ if (adj.find (node) != adj.end ())
726
+ {
727
+ for (auto elem : adj.at (node))
728
+ {
729
+ // / if the node is not visited then mark it as visited
730
+ // / and push it to the queue
731
+ if (std::find (visited.begin (), visited.end (), *(elem.first )) == visited.end ())
732
+ {
733
+ visited.push_back (*(elem.first ));
734
+ tracker.push (elem.first );
735
+ }
736
+ }
737
+ }
738
+ }
739
+ }
740
+ return visited;
741
+ }
742
+
664
743
// ostream overload
665
744
template <typename T>
666
745
std::ostream &operator <<(std::ostream &os, const Node<T> &node)
0 commit comments