diff --git a/pretext/Graphs/DijkstrasAlgorithm.ptx b/pretext/Graphs/DijkstrasAlgorithm.ptx index 67c997ef..d1221d41 100755 --- a/pretext/Graphs/DijkstrasAlgorithm.ptx +++ b/pretext/Graphs/DijkstrasAlgorithm.ptx @@ -41,6 +41,49 @@ def dijkstra(aGraph,start): pq.decreaseKey(nextVert,newDist) + + + Dijkstra's Algorithm C++ + +using namespace std; + +vector dijkstra(const vector>& graph, int start) { + vector distances; + for (int i = 0; i < graph.size(); i++) { + distances.push_back(Node(INF, -1)); + } + distances[start] = Node(0, start); + + BinHeapMap pq; + pq.insert(0, start); + + while (!pq.isEmpty()) { + Node current = pq.delMin(); + int distance = current.getKey(); + int vertex = current.getValue(); + + if (distance > distances[vertex].getKey()) { + continue; + } + + for (int i = 0; i < graph[vertex].size(); i++) { + Node neighbor = graph[vertex][i]; + + int newDistance = distance + neighbor.getKey(); + + if (newDistance < distances[neighbor.getValue()].getKey()) { + distances[neighbor.getValue()] = Node(newDistance, vertex); + pq.insert(newDistance, neighbor.getValue()); + } + } + cout << "" << endl; + } + return distances; +} + ]]> +

Dijkstra's algorithm uses a priority queue. You may recall that a priority queue is based on the heap that we implemented in the Tree Chapter. There are a couple of differences between that diff --git a/pretext/Graphs/ImplementingKnightsTour.ptx b/pretext/Graphs/ImplementingKnightsTour.ptx index 0ce14e10..ada21c57 100644 --- a/pretext/Graphs/ImplementingKnightsTour.ptx +++ b/pretext/Graphs/ImplementingKnightsTour.ptx @@ -57,6 +57,46 @@ def knightTour(n,path,u,limit): else: done = True return done + +

+ Knight's Tour Analysis C++ + & path, vector& visited, + Graph& ktGraph, int n) { + visited[currentVertex] = true; + path.push_back(currentVertex); + + if (stepCount == n * n) { + return true; // tour complete (recursive base case) + } + + vector nbrs = ktGraph.getVertex(currentVertex)->getConnections(); + for (int nbr : nbrs) { + if (!visited[nbr]) { + if (knightTour(stepCount + 1, nbr, path, visited, ktGraph, n)) { + return true; + } + } + } + + // backtrack + visited[currentVertex] = false; + path.pop_back(); + return false; +} + +vector runKnightTour(int start, Graph& ktGraph, int n){ + vector path; + vector visited(n*n, false); + + if (knightTour(1, start, path, visited, ktGraph, n)){ + return path; //if there's a successful tour + } + return {}; +} + ]]> +

Let's look at a simple example of knightTour in action. You can refer to the figures below to follow the steps of the search. For this example we will assume that the call to the getConnections diff --git a/pretext/Graphs/PrimsSpanningTreeAlgorithm.ptx b/pretext/Graphs/PrimsSpanningTreeAlgorithm.ptx index ea878dff..2dd803ce 100755 --- a/pretext/Graphs/PrimsSpanningTreeAlgorithm.ptx +++ b/pretext/Graphs/PrimsSpanningTreeAlgorithm.ptx @@ -109,6 +109,90 @@ def prim(G,start): + +

+ Prim's algorithm C++ Implementation + +#include +#include +#include +#include +#include +#include "prim.h" +using namespace std; + + +int prims(const unordered_map>& graph, int start){ + set notAdded; //S: nodes not yet in tree + set inTree; //T: nodes in MST + vector> treeEdges; //edges that form MST + + unordered_map minCost; //minimum cost to connect each node in MST + unordered_map parent; + + for (auto& v : graph) { + notAdded.insert(v.first); + minCost[v.first] = INT_MAX; //minimum cost is set to inf + parent[v.first] = -1; //the initial vertex has no parents + } + + minCost[start] = 0; //starting vertex has no cost + + //pq to select next node with the smallest edge + priority_queue, compareWeight> pq; + pq.push({start, 0}); + + cout<< "Prims starting at node "<< start << "\n\n"; + + while (!pq.empty()){ //continue looping until MST is complete + Node currentNode = pq.top(); //node with the smallest weight + pq.pop(); //remove it from the pq + int n = currentNode.vertex; //vertext to be processe + + if(notAdded.find(n) == notAdded.end()) continue; //skip if processed + + //move from S to T + notAdded.erase(n); + inTree.insert(n); //add to list of nodes in MST + + //add the connecting edge if not the starting vertex + if (parent[n] != -1){ + treeEdges.push_back({parent[n], n}); + } + + cout << "Added vertex " << n << " to MST\n"; + cout << "Current MST edges: "; + for (auto& e : treeEdges) cout << "(" << e.first << "," << e.second << ") "; + cout << "\n"; + + // Explore all neighbors of u + for (auto& edge : graph.at(n)) { + int v = edge.pointsTo; //neighbor of vertex + int weight = edge.weight; + + // Only consider vertices not in MST yet + if (notAdded.find(v) != notAdded.end() && weight < minCost[v]) { + minCost[v] = weight; + parent[v] = n; + pq.push({v, weight}); //push v and the weight to pq + } + } + } + + int totalWeight = 0; + cout << "\nFinal Minimum Spanning Tree:\n"; + for (auto& e : treeEdges) { //go through every edge pair (parent, child) + int w = minCost[e.second]; + totalWeight += w; + cout << e.first << " - " << e.second << " (weight " << w << ")\n"; + } + + return totalWeight; +} + ]]> + +

The following sequence of figures ( through ) shows the algorithm in operation on our sample tree. We begin with the starting vertex as A. The distances to all the other vertices are initialized to infinity. Looking at the neighbors of