最小生成樹—普里姆演算法(Prim演算法)和克魯斯卡爾演算法(Kruskal演算法)程式碼實現
普里姆演算法(Prim演算法)
#include<bits/stdc++.h>
using namespace std;
#define MAXVEX 100
#define INF 65535
typedef char VertexType;
typedef int EdgeType;
typedef struct {
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVertexes, numEdges;
}MGraph;
void CreateMGraph(MGraph *G) {
int m, n, w; //vm-vn的權重w
scanf("%d %d", &G->numVertexes, &G->numEdges);
for(int i = 0; i < G->numVertexes; i++) {
getchar();
scanf("%c", &G->vexs[i]);
}
for(int i = 0; i < G->numVertexes; i++) {
for(int j = 0; j < G->numVertexes; j++) {
if(i == j) G->arc[i][j] = 0;
else G->arc[i][j] = INF;
}
}
for(int k = 0; k < G->numEdges; k++) {
scanf("%d %d %d", &m, &n, &w);
G->arc[m][n] = w;
G->arc[n][m] = G->arc[m][n];
}
}
void MiniSpanTree_Prim(MGraph G) {
int min, j, k;
int arjvex[MAXVEX]; //最小邊在 U集合中的那個頂點的下標
int lowcost[MAXVEX]; // 最小邊上的權值
//初始化,從點 V0開始找最小生成樹T
arjvex[0] = 0; //arjvex[i] = j表示 V-U中集合中的 Vi點的最小邊在U集合中的點為 Vj
lowcost[0] = 0; //lowcost[i] = 0表示將點Vi納入集合 U ,lowcost[i] = w表示 V-U中 Vi點到 U的最小權值
for(int i = 1; i < G.numVertexes; i++) {
lowcost[i] = G.arc[0][i];
arjvex[i] = 0;
}
//根據最小生成樹的定義:從n個頂點中,找出 n - 1條連線,使得各邊權值最小
for(int i = 1; i < G.numVertexes; i++) {
min = INF, j = 1, k = 0;
//尋找 V-U到 U的最小權值min
for(j; j < G.numVertexes; j++) {
// lowcost[j] != 0保證頂點在 V-U中,用k記錄此時的最小權值邊在 V-U中頂點的下標
if(lowcost[j] != 0 && lowcost[j] < min) {
min = lowcost[j];
k = j;
}
}
}
printf("V[%d]-V[%d] weight = %d\n", arjvex[k], k, min);
lowcost[k] = 0; //表示將Vk納入 U
//查找鄰接矩陣Vk行的各個權值,與lowcost的對應值進行比較,若更小則更新lowcost,並將k存入arjvex數組中
for(int i = 1; i < G.numVertexes; i++) {
if(lowcost[i] != 0 && G.arc[k][i] < lowcost[i]) {
lowcost[i] = G.arc[k][i];
arjvex[i] = k;
}
}
}
int main() {
MGraph *G = (MGraph *)malloc(sizeof(MGraph));
CreateMGraph(G);
MiniSpanTree_Prim(*G);
}
/*
input:
4 5
a
b
c
d
0 1 2
0 2 2
0 3 7
1 2 4
2 3 8
output:
V[0]-V[1] weight = 2
V[0]-V[2] weight = 2
V[0]-V[3] weight = 7
最小總權值: 11
*/
時間複雜度O(n^2)
克魯斯卡爾演算法(Kruskal演算法)
#include<bits/stdc++.h>
using namespace std;
#define MAXVEX 100
#define MAXEDGE 100
#define INF 65535
typedef char VertexType;
typedef int EdgeType;
//圖的鄰接矩陣存儲結構的定義
typedef struct {
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVertexes, numEdges;
}MGraph;
//邊集數組Edge結構的定義
typedef struct {
int begin;
int end;
int weight;
}Edge;
bool vis[100][100];
void CreateMGraph(MGraph *G) {
int m, n, w; //vm-vn的權重w
scanf("%d %d", &G->numVertexes, &G->numEdges);
for(int i = 0; i < G->numVertexes; i++) {
getchar();
scanf("%c", &G->vexs[i]);
}
for(int i = 0; i < G->numVertexes; i++) {
for(int j = 0; j < G->numVertexes; j++) {
if(i == j) G->arc[i][j] = 0;
else G->arc[i][j] = INF;
}
}
for(int k = 0; k < G->numEdges; k++) {
scanf("%d %d %d", &m, &n, &w);
G->arc[m][n] = w;
G->arc[n][m] = G->arc[m][n];
}
}
void MiniSpanTree_Kruskal(MGraph G) {
int v1, v2, vs1, vs2;
Edge edges[MAXEDGE];
int parent[MAXVEX]; //標記各頂點所屬的連通分量,用於判斷邊與邊是否形成環路
//將鄰接矩陣轉換成按權值從小到大排序的邊集數組
/*
*/
int tmp = 0, m, n, ans;
ans = (G.numVertexes*G.numVertexes) / 2 - G.numVertexes / 2;
for(int k = 0; k < ans; k++) {
int min = INF, i, j;
for(i = 0; i < G.numVertexes; i++) {
for(j = 0; j < G.numVertexes; j++) {
if(!vis[i][j] && i < j && min > G.arc[i][j]) {
min = G.arc[i][j];
m = i;
n = j;
}
}
}
if(G.arc[i][j] == INF)
continue;
edges[tmp].begin = m;
edges[tmp].end = n;
edges[tmp].weight = min;
vis[m][n] = true;
tmp++;
}
//初始化為各頂點各自為一個連通分量
for(int i = 0; i < G.numVertexes; i++)
parent[i] = i;
for(int i = 0; i < G.numEdges; i++) {
//起點終點下標
v1 = edges[i].begin;
v2 = edges[i].end;
//起點終點連通分量
vs1 = parent[v1];
vs2 = parent[v2];
//邊的兩個頂點屬於不同的連通分量,列印,將新來的連通分量更改為起始點的連通分量
if(vs1 != vs2) {
printf("V[%d]-V[%d] weight:%d\n", edges[i].begin, edges[i].end, edges[i].weight);
for(int j = 0; j < G.numVertexes; j++) {
if(parent[j] == vs2) parent[j] = vs1;
}
}
}
}
int main() {
MGraph *G = (MGraph *)malloc(sizeof(MGraph));
CreateMGraph(G);
MiniSpanTree_Kruskal(*G);
}
/*
input:
4 5
a
b
c
d
0 1 2
0 2 2
0 3 7
1 2 4
2 3 8
output:
V[0]-V[1] weight:2
V[0]-V[2] weight:2
V[0]-V[3] weight:7
*/
時間複雜度O(elog2e) e為邊數