算法的原理很简单,即用贪心的思想选出据已选顶点最近顶点添加到顶点集中,本文不过多赘述,本文内容主要为该算法的C++代码实现,另外图的存储结构使用邻接矩阵。
直接上代码:
#include<iostream>
using namespace std;
#define INF 9999//假定图中所有点之间的距离都不超过这个数字
struct Arc {
int V1;
int V2;
int weight;//权重
};
class map {
int** matrix;
string* ch;//顶点对应的字符
int n;//顶点数
Arc* arc;//边
int arcnum;//边数
bool* visited;//标记顶点是否已经被访问过
int* dis;//各顶点据已访问顶点集的距离,每次顶点集有新的顶点加入,dis数组都要更新一次
int res;//最小生成树的权值
string Vmin;//这个变量为“最小顶点”,记录新加入的顶点是从哪个顶点过去的,是为了让树的生长过程更显而易见
public:
int LocateVex(string u) {
for (int i = 0; i < n; i++) {
if (u == ch[i]) {
return i;
}
}
cout << "不存在该顶点,程序运行失败";
return -1;
}
map(int n) {
this->n = n;
res = 0;
dis = new int[n];
//邻接矩阵,设置其初始值为最大值
for (int i = 0; i < n; i++)dis[i] = INF;
matrix = new int* [n];
for (int i = 0; i < n; i++) {
*(matrix + i) = new int[n];
for (int j = 0; j < n; j++)matrix[i][j] = INF;
}
//初始化visited数组,一开始全为未访问顶点
visited = new bool[n];
for (int i = 0; i < n; i++) {
visited[i] = false;
}
//输入n个顶点
ch = new string[n];
for (int i = 0; i < n; i++) {
cin >> ch[i];
}
//先输入边数
cin >> arcnum;
arc = new Arc[arcnum];
//然后按v1,v2,weight的格式输入arcnum条边及其权值
for (int i = 0; i < arcnum; i++) {
string v1, v2;
cin >> v1 >> v2;
int x = search_V(v1);
int y = search_V(v2);
//记录边两头的顶点
arc[i].V1 = x;
arc[i].V2 = y;
cin >> arc[i].weight;
//无向图
matrix[LocateVex(v1)][LocateVex(v2)] = arc[i].weight;
matrix[LocateVex(v2)][LocateVex(v1)] = arc[i].weight;
}
}
//最小生成树的生长过程中,树每一次开始生长的顶点必然是距未访问顶点集最小的顶点
//比较 新加入的顶点与未访问顶点集的距离 和 上一次距未访问顶点集距离最小的顶点距未访问顶点集的距离 哪个比较小
//若新加入的小,则更新最小顶点
void check(int t) {
int temp = INF; int t1 = 0;
for (int i = 0; i < n; i++) {
if (visited[i] && matrix[t][i] < temp) {
temp = matrix[t][i];
t1 = i;
}
}
Vmin = ch[t1];
}
void update_dis(int t) {//将t结点加入后,用t结点为准更新dis数组
for (int i = 0; i < n; i++) {
if (!visited[i] && dis[i] > matrix[t][i]) {
dis[i] = matrix[t][i];
}
}
}
//prim算法
void prim(string v) {//参数是开始建树的顶点
cout << "prim:" << endl;
//设置最小顶点为当前顶点
Vmin = v;
int i = LocateVex(v);
//标记第一个顶点已访问
visited[i] = true;
dis[i] = 0;
for (int j = 0; j < n; j++) {
if (j == i)continue;
dis[j] = min(matrix[i][j], dis[j]);
}
for (int m = 0; m < n - 1; m++) {//一共有n个结点,要把所有结点加入到生成树,所以添加n-1次
int temp = INF;
int t = 0;
for (int k = 0; k < n; k++) {//检索结点,如果未添加到树中且与树集合有连接边且新的边权重小于之前边
if (!visited[k] && dis[k] < temp) {
temp = dis[k];//则记录当前距树集合最短边权重
t = k;//记录这条边的下标
}
}
check(t);
cout << Vmin << " ";
cout << ch[t] << " ";
visited[t] = true;
res += dis[t];
cout << dis[t] << endl;
update_dis(t);//更新dis
}
//cout<<"res="<<res<<endl;//最小生成树权值
}
int search_V(string u) {
for (int i = 0; i < n; i++) {
if (u == ch[i])return i;
}
return -1;
}
~map() {
for (int i = 0; i < n; i++) {
delete[]matrix[i];
}
delete[]matrix;
delete[]arc;
delete[]dis;
delete visited;
}
};
int main() {
int n;//顶点数
cin >> n;
map a(n);
string v;
cin >> v;
//v:普利姆算法开始的顶点
a.prim(v);
}
输入样例:
6 v1 v2 v3 v4 v5 v6 10 v1 v2 6 v1 v3 1 v1 v4 5 v2 v3 5 v2 v5 3 v3 v4 5 v3 v5 6 v3 v6 4 v4 v6 2 v5 v6 6 v1
输出结果:
prim: v1 v3 1 v3 v6 4 v6 v4 2 v3 v2 5 v2 v5 3 对算法或者代码有疑问的可以评论或私信,看到了都会回