用C++分别实现了Kruskal和Boruvka算法计算MST
其中Kruskal算法中对边的排序用的heapsort
</pre><pre name="code" class="cpp">#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Edge
{
int src;
int dest;
int weight;
Edge() = default;
Edge(int s, int d, int w) : src(s), dest(d), weight(w) {};
};
struct Graph
{
int V; // number of vertices
int E; // number of edges
vector<Edge> edges; // edges start from index 1
};
struct subset
{
int parent;
int rank;
};
bool operator<(const Edge &lhs, const Edge &rhs)
{
return lhs.weight < rhs.weight;
}
bool operator<=(const Edge &lhs, const Edge &rhs)
{
return lhs.weight <= rhs.weight;
}
void max_heapfy(vector<Edge> &arry, size_t pos, size_t n)
{
auto child = pos * 2;
while (child <= n)
{
if (child < n && arry[child] < arry[child + 1])
++child;
if (arry[pos] <= arry[child])
{
swap(arry[pos], arry[child]);
pos = child;
}
else
break;
child = pos * 2;
}
}
void build_heap(vector<Edge> &arry)
{
auto n = arry.size() - 1;
for (auto i = n / 2; i >= 1; --i)
max_heapfy(arry, i, n);
}
void heap_sort(vector<Edge> &arry)
{
auto n = arry.size() - 1;
build_heap(arry);
for (vector<int>::size_type i = n; i >= 2; --i)
{
swap(arry[1], arry[i]);
max_heapfy(arry, 1, i - 1);
}
}
// union-find data structure
// use path compression techinique
int find(vector<subset> &subsets, int i)
{
if (subsets[i].parent != i)
find(subsets, subsets[i].parent);
return subsets[i].parent;
}
void Union(vector<subset> &subsets, int i, int j)
{
int iroot = find(subsets, i);
int jroot = find(subsets, j);
// union by rank;
if (subsets[iroot].rank < subsets[jroot].rank)
subsets[iroot].parent = jroot;
if (subsets[iroot].rank > subsets[jroot].rank)
subsets[jroot].parent = iroot;
if (subsets[iroot].rank == subsets[jroot].rank)
{
++subsets[iroot].rank;
subsets[jroot].parent = iroot;
}
}
// build graph from matrix to Graph
void buildGraph(vector<vector<int>> &graph, Graph &ret)
{
ret.V = static_cast<int>(graph.size());
ret.E = 0;
ret.edges.push_back(Edge(INT_MAX, INT_MAX, INT_MAX));
// edge index starts from 1
for (int i = 0; i < ret.V; ++i)
{
for (int j = 0; j < ret.V; ++j)
{
if (graph[i][j] > 0)
{
++ret.E;
ret.edges.push_back(Edge(i, j, graph[i][j]));
graph[j][i] = 0;
}
}
}
}
// judge whether exists cycle
bool isCycle(Graph &graph)
{
int V = graph.V; int E = graph.E;
vector<subset> subsets(V);
for (int i = 0; i < V; ++i)
{
subsets[i].parent = i;
subsets[i].rank = 0;
}
for (int i = 1; i <= E; ++i)
{
int src_root = find(subsets, graph.edges[i].src);
int dest_root = find(subsets, graph.edges[i].dest);
if (src_root == dest_root)
return true;
Union(subsets, src_root, dest_root);
}
return false;
}
// kruskal algorithm
vector<Edge> KruskalMST(vector<vector<int>> &matrix)
{
vector<Edge> ret;
Graph graph;
buildGraph(matrix, graph);
heap_sort(graph.edges);
vector<subset> subsets(graph.V);
for (int i = 0; i < graph.V; ++i)
{
subsets[i].parent = i;
subsets[i].rank = 0;
}
for (int i = 1; i < graph.edges.size(); ++i)
{
int src = graph.edges[i].src;
int dest = graph.edges[i].dest;
if (find(subsets, src) != find(subsets, dest))
{
ret.push_back(graph.edges[i]);
Union(subsets, src, dest);
}
}
return ret;
}
vector<Edge> BoruvkaMST(vector<vector<int>> &matrix)
{
vector<Edge> ret;
Graph graph;
buildGraph(matrix, graph);
vector<int> dist(graph.V, -1); // minimum edge for every component, this stores edges's indexes
vector<subset> subsets(graph.V);
for (int i = 0; i < graph.V; ++i)
{
subsets[i].parent = i;
subsets[i].rank = 0;
}
int v = graph.V;
while (v > 1)
{
for (int i = 1; i < graph.edges.size(); ++i)
{
int set1 = find(subsets, graph.edges[i].src);
int set2 = find(subsets, graph.edges[i].dest);
if (set1 == set2)
continue;
if (dist[set1] == -1 || graph.edges[dist[set1]].weight > graph.edges[i].weight) // check set1's minimum edge with i th edge
dist[set1] = i;
if (dist[set2] == -1 || graph.edges[dist[set2]].weight > graph.edges[i].weight) // check set2's minimum edge with i th edge
dist[set2] = i;
}
for (int i = 0; i < dist.size(); ++i)
{
if (dist[i] != -1)
{
int set1 = find(subsets, graph.edges[dist[i]].src);
int set2 = find(subsets, graph.edges[dist[i]].dest);
if (set1 == set2)
continue;
ret.push_back(graph.edges[dist[i]]);
Union(subsets, set1, set2);
--v;
}
}
}
return ret;
}
int main(int argc, const char * argv[]) {
vector<vector<int>> g = { { 0, 2, 0, 6, 0 },{ 2, 0, 3, 8, 5 },{ 0, 3, 0, 0, 7 },{ 6, 8, 0, 0, 9 },{ 0, 5, 7, 9, 0 } };
auto ret = BoruvkaMST(g);
for (auto a : ret)
cout << a.src << " to " << a.dest << endl;
cout << "-------------------------------" << endl;
auto ret2 = KruskalMST(g);
for (auto a : ret2)
cout << a.src << " to " << a.dest << endl;
system("PAUSE");
return 0;
}
Reference:
http://www.cs.princeton.edu/~wayne/kleinberg-tardos/pdf/04GreedyAlgorithmsII.pdf
http://www.geeksforgeeks.org/greedy-algorithms-set-9-boruvkas-algorithm/