C++Kruskal算法求最小生成树
刚开始写Kruskal算法时,苦于无法解决如何判断并入的最短路径是否形成回路的问题,卡了很久。后来学习了并查集的概念,才明白并查集是Kruskal算法的关键。
并查集用于判断元素是否处于同一集合中,在Kruskal算法中可用于判断是否存在环。
并查集可定义为一个一维数组parent,初始化时令parent[i]=i;即此时自身为一个单独的集合。
查询:
int Find(int x,int* visited) {
int root = x;
while (root != visited[root]) {
root = visited[root];
}
return root;
}
合并:
void merge(int begin,int end,int* parent){
int i=Find(begin,parent);
int j=Find(end,parent);
if(i!=j){
parent[j]=i;
}
}
用了并查集后就可以写Kruskal算法了,以下是Kruskal.h:
#pragma once
#include<iostream>
#include<vector>
#include"MGraph.h"
class Kruskal {
public:
Kruskal() = default;
~Kruskal() = default;
void KruskalAlgorithm(MGraph M) {
GetVEdges(M);
MySort();
for (int i = 0;i < M.NumVertexes;++i) visited.push_back(i);
for (int i = 0;i < M.NumEdges;++i) {
int Ver1 = Find(VEdges[i].begin);
int Ver2 = Find(VEdges[i].end);
if (Ver1 != Ver2) {
visited[Ver2] = Ver1;
lowest.push_back(VEdges[i].weight);
}
}
}
void Showlowest() {
int sum = 0;
for (auto x : lowest) {
cout << x << " ";
sum += x;
}
cout << endl;
cout << "Lowest:" << sum << endl;
}
private:
void GetVEdges(MGraph M) {
for (int i = 0;i < M.NumVertexes;++i) {
for (int j = 0;j < M.NumVertexes;++j) {
if (i != j && M.arc[i][j] != Infinity) {
M.arc[j][i] = Infinity;
Edges edge;
edge.begin = i;
edge.end = j;
edge.weight = M.arc[i][j];
this->VEdges.push_back(edge);
}
}
}
}//将有向图转换成无向图
void MySort() {
for (unsigned int i = 0;i < VEdges.size();++i) {
for (unsigned int j = i + 1;j < VEdges.size();++j) {
if (VEdges[j].weight < VEdges[i].weight) {
Edges temp = VEdges[i];
VEdges[i] = VEdges[j];
VEdges[j] = temp;
}
}
}
}//按权值将边排序
int Find(int x) {
int root = x;
while (root != visited[root]) {
root = visited[root];
}
return root;
}
private:
struct Edges {
int begin;
int end;
int weight;
};
private:
vector<Edges>VEdges;
vector<int>visited;
vector<int>lowest;
};