[cpp] Update weighted graph
+ totalWeight is now tracked for BFS & DFS traversals + Refactor graph search info structs
This commit is contained in:
		
							parent
							
								
									4b47630548
								
							
						
					
					
						commit
						34f12250ab
					
				@ -63,8 +63,8 @@ enum Color {
 | 
				
			|||||||
  Black
 | 
					  Black
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information used in all searches
 | 
					// Information used in all searches tracked for each node
 | 
				
			||||||
struct SearchInfo {
 | 
					struct NodeInfo {
 | 
				
			||||||
  // Coloring of the nodes is used in both DFS and BFS
 | 
					  // Coloring of the nodes is used in both DFS and BFS
 | 
				
			||||||
  Color discovered = White;
 | 
					  Color discovered = White;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -73,8 +73,8 @@ struct SearchInfo {
 | 
				
			|||||||
/******************************************************************************/
 | 
					/******************************************************************************/
 | 
				
			||||||
// BFS search information struct
 | 
					// BFS search information struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information that is only used in BFS
 | 
					// Node information that is only used in BFS
 | 
				
			||||||
struct BFS : SearchInfo {
 | 
					struct BFS : NodeInfo {
 | 
				
			||||||
  // Used to represent distance from start node
 | 
					  // Used to represent distance from start node
 | 
				
			||||||
  int distance = 0;
 | 
					  int distance = 0;
 | 
				
			||||||
  // Used to represent the parent node that discovered this node
 | 
					  // Used to represent the parent node that discovered this node
 | 
				
			||||||
@ -90,8 +90,8 @@ using InfoBFS = std::unordered_map<int, struct BFS>;
 | 
				
			|||||||
/******************************************************************************/
 | 
					/******************************************************************************/
 | 
				
			||||||
// DFS search information struct
 | 
					// DFS search information struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information that is only used in DFS
 | 
					// Node information that is only used in DFS
 | 
				
			||||||
struct DFS : SearchInfo {
 | 
					struct DFS : NodeInfo {
 | 
				
			||||||
  // Create a pair to track discovery / finish time
 | 
					  // Create a pair to track discovery / finish time
 | 
				
			||||||
  // + Discovery time is the iteration the node is first discovered
 | 
					  // + Discovery time is the iteration the node is first discovered
 | 
				
			||||||
  // + Finish time is the iteration the node has been checked completely
 | 
					  // + Finish time is the iteration the node has been checked completely
 | 
				
			||||||
@ -119,7 +119,7 @@ public:
 | 
				
			|||||||
  // An alternate DFS that checks each node of the graph beginning at startNode
 | 
					  // An alternate DFS that checks each node of the graph beginning at startNode
 | 
				
			||||||
  InfoDFS DFS(const Node &startNode) const;
 | 
					  InfoDFS DFS(const Node &startNode) const;
 | 
				
			||||||
  // Visit function is used in both versions of DFS
 | 
					  // Visit function is used in both versions of DFS
 | 
				
			||||||
  void DFSVisit(int &time, const Node& startNode, InfoDFS &searchInfo) const;
 | 
					  void DFSVisit(int &time, const Node& startNode, InfoDFS &dfs) const;
 | 
				
			||||||
  // Topological sort, using DFS
 | 
					  // Topological sort, using DFS
 | 
				
			||||||
  std::vector<Node> TopologicalSort(const Node &startNode) const;
 | 
					  std::vector<Node> TopologicalSort(const Node &startNode) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -79,8 +79,8 @@ enum Color {
 | 
				
			|||||||
  Black
 | 
					  Black
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information used in all searches
 | 
					// Information used in all searches tracked for each node
 | 
				
			||||||
struct SearchInfo {
 | 
					struct NodeInfo {
 | 
				
			||||||
  // Coloring of the nodes is used in both DFS and BFS
 | 
					  // Coloring of the nodes is used in both DFS and BFS
 | 
				
			||||||
  Color discovered = White;
 | 
					  Color discovered = White;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -89,9 +89,9 @@ struct SearchInfo {
 | 
				
			|||||||
/******************************************************************************/
 | 
					/******************************************************************************/
 | 
				
			||||||
// BFS search information struct
 | 
					// BFS search information struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information that is only used in BFS
 | 
					// Node information that is only used in BFS
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
struct BFS : SearchInfo {
 | 
					struct BFS : NodeInfo {
 | 
				
			||||||
  // Used to represent distance from start node
 | 
					  // Used to represent distance from start node
 | 
				
			||||||
  int distance = 0;
 | 
					  int distance = 0;
 | 
				
			||||||
  // Used to represent the parent node that discovered this node
 | 
					  // Used to represent the parent node that discovered this node
 | 
				
			||||||
@ -107,8 +107,8 @@ template <typename T> using InfoBFS = std::unordered_map<T, struct BFS<T>>;
 | 
				
			|||||||
/******************************************************************************/
 | 
					/******************************************************************************/
 | 
				
			||||||
// DFS search information struct
 | 
					// DFS search information struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information that is only used in DFS
 | 
					// Node information that is only used in DFS
 | 
				
			||||||
struct DFS : SearchInfo {
 | 
					struct DFS : NodeInfo {
 | 
				
			||||||
  // Create a pair to track discovery / finish time
 | 
					  // Create a pair to track discovery / finish time
 | 
				
			||||||
  // + Discovery time is the iteration the node is first discovered
 | 
					  // + Discovery time is the iteration the node is first discovered
 | 
				
			||||||
  // + Finish time is the iteration the node has been checked completely
 | 
					  // + Finish time is the iteration the node has been checked completely
 | 
				
			||||||
@ -125,7 +125,7 @@ template <typename T> using InfoDFS = std::unordered_map<T, struct DFS>;
 | 
				
			|||||||
// Edges stored as multimap<weight, pair<nodeA.data_, nodeB.data_>>
 | 
					// Edges stored as multimap<weight, pair<nodeA.data_, nodeB.data_>>
 | 
				
			||||||
template <typename T> using Edges = std::multimap<int, std::pair<T, T>>;
 | 
					template <typename T> using Edges = std::multimap<int, std::pair<T, T>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct MST : SearchInfo {
 | 
					struct MST : NodeInfo {
 | 
				
			||||||
  int32_t parent = INT32_MIN;
 | 
					  int32_t parent = INT32_MIN;
 | 
				
			||||||
  int rank = 0;
 | 
					  int rank = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -156,11 +156,19 @@ int main (const int argc, const char * argv[])
 | 
				
			|||||||
          {9, {{3, 2}, {7, 6}}}
 | 
					          {9, {{3, 2}, {7, 6}}}
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					  std::cout << "\nChecking weight traversing graph from node 1 using DFS...\n";
 | 
				
			||||||
 | 
					  InfoDFS resultDFS = graphMST.DFS(graphMST.GetNodeCopy(1));
 | 
				
			||||||
 | 
					  std::cout << "DFS total weight traversed: " << resultDFS.totalWeight << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::cout << "\nChecking weight traversing graph from node 1 using BFS...\n";
 | 
				
			||||||
 | 
					  InfoBFS resultBFS = graphMST.BFS(graphMST.GetNodeCopy(1));
 | 
				
			||||||
 | 
					  std::cout << "BFS total weight traversed: " << resultBFS.totalWeight << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  InfoMST resultMST = graphMST.KruskalMST();
 | 
					  InfoMST resultMST = graphMST.KruskalMST();
 | 
				
			||||||
  std::cout << "Finding MST using Kruskal's...\n\nMST result: \n";
 | 
					  std::cout << "\n\nFinding MST using Kruskal's...\n\nMST result: \n";
 | 
				
			||||||
  for (const auto &edge : resultMST.edgesMST) {
 | 
					  for (const auto &edge : resultMST.edgesMST) {
 | 
				
			||||||
    std::cout << "Connected nodes: " << edge.second.first << "->"
 | 
					    std::cout << "Connected nodes: " << edge.second.first << "->"
 | 
				
			||||||
              << edge.second.second << " with weight of " << edge.first << "\n";
 | 
					              << edge.second.second << " with weight of " << edge.first << "\n";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  std::cout << "Total MST weight: " << resultMST.weightMST << std::endl;
 | 
					  std::cout << "Total MST weight: " << resultMST.totalWeight << std::endl;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,13 +14,13 @@
 | 
				
			|||||||
InfoBFS Graph::BFS(const Node& startNode) const
 | 
					InfoBFS Graph::BFS(const Node& startNode) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // Create local object to track the information gathered during traversal
 | 
					  // Create local object to track the information gathered during traversal
 | 
				
			||||||
  InfoBFS searchInfo;
 | 
					  InfoBFS bfs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Create a queue to visit discovered nodes in FIFO order
 | 
					  // Create a queue to visit discovered nodes in FIFO order
 | 
				
			||||||
  std::queue<const Node *> visitQueue;
 | 
					  std::queue<const Node *> visitQueue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Mark the startNode as in progress until we finish checking adjacent nodes
 | 
					  // Mark the startNode as in progress until we finish checking adjacent nodes
 | 
				
			||||||
  searchInfo[startNode.number].discovered = Gray;
 | 
					  bfs.nodeInfo[startNode.number].discovered = Gray;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Visit the startNode
 | 
					  // Visit the startNode
 | 
				
			||||||
  visitQueue.push(&startNode);
 | 
					  visitQueue.push(&startNode);
 | 
				
			||||||
@ -31,17 +31,17 @@ InfoBFS Graph::BFS(const Node& startNode) const
 | 
				
			|||||||
    const Node * thisNode = visitQueue.front();
 | 
					    const Node * thisNode = visitQueue.front();
 | 
				
			||||||
    visitQueue.pop();
 | 
					    visitQueue.pop();
 | 
				
			||||||
    std::cout << "Visiting node " << thisNode->number << std::endl;
 | 
					    std::cout << "Visiting node " << thisNode->number << std::endl;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Check if we have already discovered all the adjacentNodes to thisNode
 | 
					    // Check if we have already discovered all the adjacentNodes to thisNode
 | 
				
			||||||
    for (const auto &adjacent : thisNode->adjacent) {
 | 
					    for (const auto &adjacent : thisNode->adjacent) {
 | 
				
			||||||
      if (searchInfo[adjacent.first].discovered == White) {
 | 
					      if (bfs.nodeInfo[adjacent.first].discovered == White) {
 | 
				
			||||||
        std::cout << "Found undiscovered adjacentNode: " << adjacent.first
 | 
					        std::cout << "Found undiscovered adjacentNode: " << adjacent.first
 | 
				
			||||||
                  << "\n";
 | 
					                  << " with weight of " << adjacent.second << std::endl;
 | 
				
			||||||
 | 
					        bfs.totalWeight += adjacent.second;
 | 
				
			||||||
        // Mark the adjacent node as in progress
 | 
					        // Mark the adjacent node as in progress
 | 
				
			||||||
        searchInfo[adjacent.first].discovered = Gray;
 | 
					        bfs.nodeInfo[adjacent.first].discovered = Gray;
 | 
				
			||||||
        searchInfo[adjacent.first].distance =
 | 
					        bfs.nodeInfo[adjacent.first].distance =
 | 
				
			||||||
            searchInfo[thisNode->number].distance + 1;
 | 
					            bfs.nodeInfo[thisNode->number].distance + 1;
 | 
				
			||||||
        searchInfo[adjacent.first].predecessor =
 | 
					        bfs.nodeInfo[adjacent.first].predecessor =
 | 
				
			||||||
            &GetNode(thisNode->number);
 | 
					            &GetNode(thisNode->number);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Add the discovered node the the visitQueue
 | 
					        // Add the discovered node the the visitQueue
 | 
				
			||||||
@ -49,11 +49,11 @@ InfoBFS Graph::BFS(const Node& startNode) const
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // We are finished with this node and the adjacent nodes; Mark it discovered
 | 
					    // We are finished with this node and the adjacent nodes; Mark it discovered
 | 
				
			||||||
    searchInfo[thisNode->number].discovered = Black;
 | 
					    bfs.nodeInfo[thisNode->number].discovered = Black;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Return the information gathered from this search, JIC caller needs it
 | 
					  // Return the information gathered from this search, JIC caller needs it
 | 
				
			||||||
  return searchInfo;
 | 
					  return bfs;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
 | 
					std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
 | 
				
			||||||
@ -62,8 +62,8 @@ std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
 | 
				
			|||||||
  // + If the caller modifies these, it will not impact the graph's data
 | 
					  // + If the caller modifies these, it will not impact the graph's data
 | 
				
			||||||
  std::deque<Node> path;
 | 
					  std::deque<Node> path;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  InfoBFS searchInfo = BFS(start);
 | 
					  InfoBFS bfs = BFS(start);
 | 
				
			||||||
  const Node * next = searchInfo[finish.number].predecessor;
 | 
					  const Node * next = bfs.nodeInfo[finish.number].predecessor;
 | 
				
			||||||
  bool isValid = false;
 | 
					  bool isValid = false;
 | 
				
			||||||
  do {
 | 
					  do {
 | 
				
			||||||
    // If we have reached the start node, we have found a valid path
 | 
					    // If we have reached the start node, we have found a valid path
 | 
				
			||||||
@ -74,7 +74,7 @@ std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
 | 
				
			|||||||
    path.emplace_front(*next);
 | 
					    path.emplace_front(*next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Move to the next node
 | 
					    // Move to the next node
 | 
				
			||||||
    next = searchInfo[next->number].predecessor;
 | 
					    next = bfs.nodeInfo[next->number].predecessor;
 | 
				
			||||||
  } while (next != nullptr);
 | 
					  } while (next != nullptr);
 | 
				
			||||||
  // Use emplace_back to call Node copy constructor
 | 
					  // Use emplace_back to call Node copy constructor
 | 
				
			||||||
  path.emplace_back(finish);
 | 
					  path.emplace_back(finish);
 | 
				
			||||||
@ -89,85 +89,83 @@ std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
 | 
				
			|||||||
InfoDFS Graph::DFS() const
 | 
					InfoDFS Graph::DFS() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // Track the nodes we have discovered
 | 
					  // Track the nodes we have discovered
 | 
				
			||||||
  InfoDFS searchInfo;
 | 
					  InfoDFS dfs;
 | 
				
			||||||
  int time = 0;
 | 
					  int time = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Visit each node in the graph
 | 
					  // Visit each node in the graph
 | 
				
			||||||
  for (const auto& node : nodes_) {
 | 
					  for (const auto & node : nodes_) {
 | 
				
			||||||
    std::cout << "Visiting node " << node.number << std::endl;
 | 
					    std::cout << "Visiting node " << node.number << std::endl;
 | 
				
			||||||
    // If the node is undiscovered, visit it
 | 
					    // If the node is undiscovered, visit it
 | 
				
			||||||
    if (searchInfo[node.number].discovered == White) {
 | 
					    if (dfs.nodeInfo[node.number].discovered == White) {
 | 
				
			||||||
      std::cout << "Found undiscovered node: " << node.number << std::endl;
 | 
					      std::cout << "Found undiscovered node: " << node.number << std::endl;
 | 
				
			||||||
      // Visiting the undiscovered node will check it's adjacent nodes
 | 
					      // Visiting the undiscovered node will check it's adjacent nodes
 | 
				
			||||||
      DFSVisit(time, node, searchInfo);
 | 
					      DFSVisit(time, node, dfs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return searchInfo;
 | 
					  return dfs;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
InfoDFS Graph::DFS(const Node &startNode) const
 | 
					InfoDFS Graph::DFS(const Node &startNode) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  // Track the nodes we have discovered
 | 
					  // Track the nodes we have discovered
 | 
				
			||||||
  InfoDFS searchInfo;
 | 
					  InfoDFS dfs;
 | 
				
			||||||
  int time = 0;
 | 
					  int time = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto startIter = std::find(nodes_.begin(), nodes_.end(),
 | 
					  auto startIter =
 | 
				
			||||||
                             Node(startNode.number, {})
 | 
					      std::find(nodes_.begin(), nodes_.end(), Node(startNode.number, { }));
 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // beginning at startNode, visit each node in the graph until we reach the end
 | 
					  // beginning at startNode, visit each node in the graph until we reach the end
 | 
				
			||||||
  while (startIter != nodes_.end()) {
 | 
					  while (startIter != nodes_.end()) {
 | 
				
			||||||
    std::cout << "Visiting node " << startIter->number << std::endl;
 | 
					    std::cout << "Visiting node " << startIter->number << std::endl;
 | 
				
			||||||
    // If the startIter is undiscovered, visit it
 | 
					    // If the startIter is undiscovered, visit it
 | 
				
			||||||
    if (searchInfo[startIter->number].discovered == White) {
 | 
					    if (dfs.nodeInfo[startIter->number].discovered == White) {
 | 
				
			||||||
      std::cout << "Found undiscovered node: " << startIter->number << std::endl;
 | 
					      std::cout << "Found undiscovered node: " << startIter->number
 | 
				
			||||||
 | 
					                << std::endl;
 | 
				
			||||||
      // Visiting the undiscovered node will check it's adjacent nodes
 | 
					      // Visiting the undiscovered node will check it's adjacent nodes
 | 
				
			||||||
      DFSVisit(time, *startIter, searchInfo);
 | 
					      DFSVisit(time, *startIter, dfs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    startIter++;
 | 
					    startIter++;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Once we reach the last node, check the beginning for unchecked nodes
 | 
					  // Once we reach the last node, check the beginning for unchecked nodes
 | 
				
			||||||
  startIter = nodes_.begin();
 | 
					  startIter = nodes_.begin();
 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Once we reach the initial startNode, we have checked all nodes
 | 
					  // Once we reach the initial startNode, we have checked all nodes
 | 
				
			||||||
  while (*startIter != startNode) {
 | 
					  while (*startIter != startNode) {
 | 
				
			||||||
    std::cout << "Visiting node " << startIter->number << std::endl;
 | 
					    std::cout << "Visiting node " << startIter->number << std::endl;
 | 
				
			||||||
    // If the startIter is undiscovered, visit it
 | 
					    // If the startIter is undiscovered, visit it
 | 
				
			||||||
    if (searchInfo[startIter->number].discovered == White) {
 | 
					    if (dfs.nodeInfo[startIter->number].discovered == White) {
 | 
				
			||||||
      std::cout << "Found undiscovered node: " << startIter->number << std::endl;
 | 
					      std::cout << "Found undiscovered node: " << startIter->number << std::endl;
 | 
				
			||||||
      // Visiting the undiscovered node will check it's adjacent nodes
 | 
					      // Visiting the undiscovered node will check it's adjacent nodes
 | 
				
			||||||
      DFSVisit(time, *startIter, searchInfo);
 | 
					      DFSVisit(time, *startIter, dfs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    startIter++;
 | 
					    startIter++;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return searchInfo;
 | 
					  return dfs;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Graph::DFSVisit(int &time, const Node& startNode, InfoDFS &searchInfo) const
 | 
					void Graph::DFSVisit(int &time, const Node& startNode, InfoDFS &dfs) const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  searchInfo[startNode.number].discovered = Gray;
 | 
					  dfs.nodeInfo[startNode.number].discovered = Gray;
 | 
				
			||||||
  time++;
 | 
					  time++;
 | 
				
			||||||
  searchInfo[startNode.number].discoveryFinish.first = time;
 | 
					  dfs.nodeInfo[startNode.number].discoveryFinish.first = time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Check the adjacent nodes of the startNode
 | 
					  // Check the adjacent nodes of the startNode
 | 
				
			||||||
  for (const auto &adjacent : startNode.adjacent) {
 | 
					  for (const auto & adjacent : startNode.adjacent) {
 | 
				
			||||||
    auto iter = std::find(nodes_.begin(), nodes_.end(),
 | 
					    const auto node = GetNode(adjacent.first);
 | 
				
			||||||
                          Node(adjacent.first, {}));
 | 
					 | 
				
			||||||
    // If the adjacentNode is undiscovered, visit it
 | 
					    // If the adjacentNode is undiscovered, visit it
 | 
				
			||||||
    // + Offset by 1 to account for 0 index of discovered vector
 | 
					    // + Offset by 1 to account for 0 index of discovered vector
 | 
				
			||||||
    if (searchInfo[iter->number].discovered == White) {
 | 
					    if (dfs.nodeInfo[node.number].discovered == White) {
 | 
				
			||||||
      std::cout << "Found undiscovered adjacentNode: "
 | 
					      std::cout << "Found undiscovered adjacentNode: " << adjacent.first
 | 
				
			||||||
                << GetNode(adjacent.first).number << std::endl;
 | 
					                << " with weight of " << adjacent.second << std::endl;
 | 
				
			||||||
      // Visiting the undiscovered node will check it's adjacent nodes
 | 
					      // Visiting the undiscovered node will check it's adjacent nodes
 | 
				
			||||||
      DFSVisit(time, *iter, searchInfo);
 | 
					      dfs.totalWeight += adjacent.second;
 | 
				
			||||||
 | 
					      DFSVisit(time, node, dfs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  searchInfo[startNode.number].discovered = Black;
 | 
					  dfs.nodeInfo[startNode.number].discovered = Black;
 | 
				
			||||||
  time++;
 | 
					  time++;
 | 
				
			||||||
  searchInfo[startNode.number].discoveryFinish.second = time;
 | 
					  dfs.nodeInfo[startNode.number].discoveryFinish.second = time;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<Node> Graph::TopologicalSort(const Node &startNode) const
 | 
					std::vector<Node> Graph::TopologicalSort(const Node &startNode) const
 | 
				
			||||||
@ -177,8 +175,8 @@ std::vector<Node> Graph::TopologicalSort(const Node &startNode) const
 | 
				
			|||||||
  std::vector<Node> order(nodes_);
 | 
					  std::vector<Node> order(nodes_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto comp = [&topological](const Node &a, const Node &b) {
 | 
					  auto comp = [&topological](const Node &a, const Node &b) {
 | 
				
			||||||
    return (topological[a.number].discoveryFinish.second <
 | 
					    return (topological.nodeInfo[a.number].discoveryFinish.second <
 | 
				
			||||||
      topological[b.number].discoveryFinish.second);
 | 
					            topological.nodeInfo[b.number].discoveryFinish.second);
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::sort(order.begin(), order.end(), comp);
 | 
					  std::sort(order.begin(), order.end(), comp);
 | 
				
			||||||
@ -190,26 +188,26 @@ std::vector<Node> Graph::TopologicalSort(const Node &startNode) const
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
InfoMST Graph::KruskalMST() const
 | 
					InfoMST Graph::KruskalMST() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  InfoMST searchInfo(nodes_);
 | 
					  InfoMST mst(nodes_);
 | 
				
			||||||
  // The ctor for InfoMST initializes all edges within the graph into a multimap
 | 
					  // The ctor for InfoMST initializes all edges within the graph into a multimap
 | 
				
			||||||
  // + Key for multimap is edge weight, so they're already sorted in ascending
 | 
					  // + Key for multimap is edge weight, so they're already sorted in ascending
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // For each edge in the graph, check if they are part of the same tree
 | 
					  // For each edge in the graph, check if they are part of the same tree
 | 
				
			||||||
  // + Since we do not want to create a cycle in the MST forest -
 | 
					  // + Since we do not want to create a cycle in the MST forest -
 | 
				
			||||||
  // + we don't connect nodes that are part of the same tree
 | 
					  // + we don't connect nodes that are part of the same tree
 | 
				
			||||||
  for (const auto &edge : searchInfo.edges) {
 | 
					  for (const auto &edge : mst.edges) {
 | 
				
			||||||
    // Two integers representing the node.number for the connected nodes
 | 
					    // Two integers representing the node.number for the connected nodes
 | 
				
			||||||
    const int u = edge.second.first;
 | 
					    const int u = edge.second.first;
 | 
				
			||||||
    const int v = edge.second.second;
 | 
					    const int v = edge.second.second;
 | 
				
			||||||
    // Check if the nodes are of the same tree
 | 
					    // Check if the nodes are of the same tree
 | 
				
			||||||
    if (searchInfo.FindSet(u) != searchInfo.FindSet(v)) {
 | 
					    if (mst.FindSet(u) != mst.FindSet(v)) {
 | 
				
			||||||
      // If they are not, add the edge to our MST
 | 
					      // If they are not, add the edge to our MST
 | 
				
			||||||
      searchInfo.edgesMST.emplace(edge);
 | 
					      mst.edgesMST.emplace(edge);
 | 
				
			||||||
      searchInfo.weightMST += edge.first;
 | 
					      mst.totalWeight += edge.first;
 | 
				
			||||||
      // Update the forest to reflect this change
 | 
					      // Update the forest to reflect this change
 | 
				
			||||||
      searchInfo.Union(u, v);
 | 
					      mst.Union(u, v);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return searchInfo;
 | 
					  return mst;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -69,18 +69,29 @@ enum Color {
 | 
				
			|||||||
  Black
 | 
					  Black
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information used in all searches
 | 
					// Information used in all searches tracked for each node
 | 
				
			||||||
struct SearchInfo {
 | 
					struct NodeInfo {
 | 
				
			||||||
  // Coloring of the nodes is used in both DFS and BFS
 | 
					  // Coloring of the nodes is used in both DFS and BFS
 | 
				
			||||||
  Color discovered = White;
 | 
					  Color discovered = White;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Template for tracking graph information gathered during traversals
 | 
				
			||||||
 | 
					// + Used for DFS, BFS, and MST
 | 
				
			||||||
 | 
					template <typename T>
 | 
				
			||||||
 | 
					struct GraphInfo {
 | 
				
			||||||
 | 
					  // Store search information in unordered_maps so we can pass it around easily
 | 
				
			||||||
 | 
					  // + Allows each node to store relative information on the traversal
 | 
				
			||||||
 | 
					  std::unordered_map<int, T> nodeInfo;
 | 
				
			||||||
 | 
					  // Track total weight for all traversals
 | 
				
			||||||
 | 
					  int totalWeight = 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/******************************************************************************/
 | 
					/******************************************************************************/
 | 
				
			||||||
// BFS search information struct
 | 
					// BFS search information struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information that is only used in BFS
 | 
					// Node search information that is only used in BFS
 | 
				
			||||||
struct BFS : SearchInfo {
 | 
					struct BFS : NodeInfo {
 | 
				
			||||||
  // Used to represent distance from start node
 | 
					  // Used to represent distance from start node
 | 
				
			||||||
  int distance = 0;
 | 
					  int distance = 0;
 | 
				
			||||||
  // Used to represent the parent node that discovered this node
 | 
					  // Used to represent the parent node that discovered this node
 | 
				
			||||||
@ -88,16 +99,14 @@ struct BFS : SearchInfo {
 | 
				
			|||||||
  const Node *predecessor = nullptr;
 | 
					  const Node *predecessor = nullptr;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Store search information in unordered_maps so we can pass it around easily
 | 
					struct InfoBFS : GraphInfo<BFS> {/* Members inherited from GraphInfo */};
 | 
				
			||||||
// + Allows each node to store relative information on the traversal
 | 
					 | 
				
			||||||
using InfoBFS = std::unordered_map<int, struct BFS>;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/******************************************************************************/
 | 
					/******************************************************************************/
 | 
				
			||||||
// DFS search information struct
 | 
					// DFS search information struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Information that is only used in DFS
 | 
					// Information that is only used in DFS
 | 
				
			||||||
struct DFS : SearchInfo {
 | 
					struct DFS : NodeInfo {
 | 
				
			||||||
  // Create a pair to track discovery / finish time
 | 
					  // Create a pair to track discovery / finish time
 | 
				
			||||||
  // + Discovery time is the iteration the node is first discovered
 | 
					  // + Discovery time is the iteration the node is first discovered
 | 
				
			||||||
  // + Finish time is the iteration the node has been checked completely
 | 
					  // + Finish time is the iteration the node has been checked completely
 | 
				
			||||||
@ -105,18 +114,19 @@ struct DFS : SearchInfo {
 | 
				
			|||||||
  std::pair<int, int> discoveryFinish;
 | 
					  std::pair<int, int> discoveryFinish;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct InfoDFS : GraphInfo<DFS> {/* Members inherited from GraphInfo */};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/******************************************************************************/
 | 
					/******************************************************************************/
 | 
				
			||||||
// MST search information struct
 | 
					// MST search information struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct MST : SearchInfo {
 | 
					struct MST : NodeInfo {
 | 
				
			||||||
  int32_t parent = INT32_MIN;
 | 
					  int32_t parent = INT32_MIN;
 | 
				
			||||||
  int rank = 0;
 | 
					  int rank = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
using InfoDFS = std::unordered_map<int, struct DFS>;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
using Edges = std::multimap<int, std::pair<int, int>>;
 | 
					using Edges = std::multimap<int, std::pair<int, int>>;
 | 
				
			||||||
struct InfoMST {
 | 
					struct InfoMST : GraphInfo<MST>{
 | 
				
			||||||
  explicit InfoMST(const std::vector<Node> &nodes)
 | 
					  explicit InfoMST(const std::vector<Node> &nodes)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    for (const auto &node : nodes) {
 | 
					    for (const auto &node : nodes) {
 | 
				
			||||||
@ -134,20 +144,17 @@ struct InfoMST {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::unordered_map<int, struct MST> searchInfo;
 | 
					 | 
				
			||||||
  // All of the edges within our graph
 | 
					  // All of the edges within our graph
 | 
				
			||||||
  // + Since each node stores its own edges, this is initialized in InfoMST ctor
 | 
					  // + Since each node stores its own edges, this is initialized in InfoMST ctor
 | 
				
			||||||
  Edges edges;
 | 
					  Edges edges;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // A multimap of the edges found for our MST
 | 
					  // A multimap of the edges found for our MST
 | 
				
			||||||
  Edges edgesMST;
 | 
					  Edges edgesMST;
 | 
				
			||||||
  // The total weight of our resulting MST
 | 
					 | 
				
			||||||
  int weightMST = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void MakeSet(int x)
 | 
					  void MakeSet(int x)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    searchInfo[x].parent = x;
 | 
					    nodeInfo[x].parent = x;
 | 
				
			||||||
    searchInfo[x].rank = 0;
 | 
					    nodeInfo[x].rank = 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void Union(int x, int y)
 | 
					  void Union(int x, int y)
 | 
				
			||||||
@ -157,23 +164,23 @@ struct InfoMST {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void Link(int x, int y)
 | 
					  void Link(int x, int y)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (searchInfo[x].rank > searchInfo[y].rank) {
 | 
					    if (nodeInfo[x].rank > nodeInfo[y].rank) {
 | 
				
			||||||
      searchInfo[y].parent = x;
 | 
					      nodeInfo[y].parent = x;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      searchInfo[x].parent = y;
 | 
					      nodeInfo[x].parent = y;
 | 
				
			||||||
      if (searchInfo[x].rank == searchInfo[y].rank) {
 | 
					      if (nodeInfo[x].rank == nodeInfo[y].rank) {
 | 
				
			||||||
        searchInfo[y].rank += 1;
 | 
					        nodeInfo[y].rank += 1;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int FindSet(int x)
 | 
					  int FindSet(int x)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (x != searchInfo[x].parent) {
 | 
					    if (x != nodeInfo[x].parent) {
 | 
				
			||||||
      searchInfo[x].parent = FindSet(searchInfo[x].parent);
 | 
					      nodeInfo[x].parent = FindSet(nodeInfo[x].parent);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return searchInfo[x].parent;
 | 
					    return nodeInfo[x].parent;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -195,7 +202,7 @@ public:
 | 
				
			|||||||
  // An alternate DFS that checks each node of the graph beginning at startNode
 | 
					  // An alternate DFS that checks each node of the graph beginning at startNode
 | 
				
			||||||
  InfoDFS DFS(const Node &startNode) const;
 | 
					  InfoDFS DFS(const Node &startNode) const;
 | 
				
			||||||
  // Visit function is used in both versions of DFS
 | 
					  // Visit function is used in both versions of DFS
 | 
				
			||||||
  void DFSVisit(int &time, const Node& startNode, InfoDFS &searchInfo) const;
 | 
					  void DFSVisit(int &time, const Node& startNode, InfoDFS &dfs) const;
 | 
				
			||||||
  // Topological sort, using DFS
 | 
					  // Topological sort, using DFS
 | 
				
			||||||
  std::vector<Node> TopologicalSort(const Node &startNode) const;
 | 
					  std::vector<Node> TopologicalSort(const Node &startNode) const;
 | 
				
			||||||
  // Kruskal's MST
 | 
					  // Kruskal's MST
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user