|
#include "Prim.h" |
|
|
|
#include <assert.h> // for assert |
|
|
|
const int INF = ((unsigned int) ~0) >> 1; // Infinity: The max value of int. |
|
|
|
Prim::Prim(Graph aGraph) |
|
: MST(aGraph) |
|
{ |
|
Compute(); |
|
} |
|
|
|
Prim::~Prim() |
|
{ |
|
} |
|
|
|
void |
|
Prim::ConvertGraph() |
|
{ |
|
assert(mGraph.mVertices && !mGraph.mEdges.empty() && mAdjacentEdges.empty()); |
|
|
|
mAdjacentEdges.resize(mGraph.mVertices); |
|
for (auto e: mGraph.mEdges) { // e: edge(u, v) = w |
|
assert(!e.mDirected); // We only handle the undirected graph in Prim. |
|
unsigned int u = e.mFrom; |
|
unsigned int v = e.mTo; |
|
// edge(u -> v) = w |
|
mAdjacentEdges[u].push_back(Edge(u, v, e.mWeight, true)); |
|
// edge(v -> u) = w |
|
mAdjacentEdges[v].push_back(Edge(v, u, e.mWeight, true)); |
|
} |
|
} |
|
|
|
void |
|
Prim::Compute() |
|
{ |
|
// We must have N - 1 edges at least to form the spanning tree, |
|
// where N is the number of vertices. |
|
assert(mGraph.mVertices && |
|
mGraph.mEdges.size() >= mGraph.mVertices - 1 && |
|
mQueue.empty()); |
|
|
|
ConvertGraph(); |
|
|
|
// Indicating whether the vertex is visited or not. |
|
std::vector<bool> visited(mGraph.mVertices, false); |
|
|
|
// Track the distances between unvisited vertices to the spanning tree. |
|
std::vector<int> distances(mGraph.mVertices, INF); |
|
|
|
// Take vertex 0 as the beginning vertex to form the spanning tree. |
|
unsigned int start = 0; |
|
distances[start] = 0; |
|
mQueue.push(Edge(start, start, 0, true)); |
|
|
|
while (!mQueue.empty()) { |
|
// Pick the vertex that has minimal distance to the spanning tree. |
|
unsigned int nearest = mQueue.top().mTo; |
|
|
|
// Suppose there are two edges connected to a vertex v: |
|
// edge(u, v) = w, edge(u', v) = w' and w' < w. |
|
// If edge(u, v) is pushed into queue before edge(u', v), |
|
// then edge(u, v) should be skipped after edge(u', v) is popped. |
|
if (visited[nearest]) { |
|
mQueue.pop(); |
|
continue; |
|
} |
|
|
|
// Update the weight sum and record the picked edge that can form the MST. |
|
if (nearest == start) { |
|
// The weight sum should be 0 at first. |
|
assert(!mQueue.top().mWeight && !mCost); |
|
} else { |
|
assert(!visited[nearest]); |
|
visited[nearest] = true; |
|
mCost += mQueue.top().mWeight; |
|
assert(mQueue.top().mWeight == distances[nearest]); |
|
mEdges.push_back(mQueue.top()); |
|
} |
|
|
|
// It's finished if there are already N - 1 edges. |
|
if (mEdges.size() == mGraph.mVertices - 1) { |
|
break; |
|
} |
|
|
|
// Add to the nearest vertex to the spanning tree and update |
|
// all the distances from the vertices to the tree formed so far. |
|
mQueue.pop(); |
|
for (auto e: mAdjacentEdges[nearest]) { |
|
assert(e.mFrom == nearest); |
|
// Use !visited[e.mTo] to avoid re-pushing the edge that has been added. |
|
if (!visited[e.mTo] && e.mWeight < distances[e.mTo]) { |
|
distances[e.mTo] = e.mWeight; |
|
// Use edge weight as the priority so the edge |
|
// with minimal weight will be on the top of the priority queue. |
|
mQueue.push(e); |
|
} |
|
} |
|
} |
|
} |