前言
这两个算法比较好理解,实现起来也没那么困难,相信看到这篇博客的都是学了数据结构了的,所以我就不重复解释这两个算法的思路了。
这两个代码其实是我在数据结构实验课写的代码,应该可以借鉴点吧。
Prim算法
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define MaxVertexNum 100//最大顶点数
#define INFINITY 65535
typedef int Vertex;//用顶点下标表示顶点
typedef int WeightType;//定义权值类型
typedef char DataType;
int visited[105];
typedef struct GNode {//图结点的定义
int Nv;//顶点数
int Ne;//边数
WeightType G[MaxVertexNum][MaxVertexNum];//邻接矩阵
DataType Data[MaxVertexNum];//存顶点的数据
}*MGraph;
typedef struct ENode {//边的定义
Vertex V1, V2;//有向边
WeightType Weight;//权重
}*Edge;
MGraph CreateGraph(int Nv, int Ne) {//初始化一个有VertexNum个顶点但没有边的图
MGraph Graph = (MGraph)malloc(sizeof(struct GNode));//建立图
Graph->Nv = Nv;
Graph->Ne = Ne;
//初始化邻接矩阵
for (Vertex V = 0; V < Graph->Nv; V++)
for (Vertex W = 0; W < Graph->Nv; W++)
Graph->G[V][W] = INFINITY;
for (int i = 0; i < Nv; i++)Graph->Data[i] = i;//顶点表
return Graph;
}
void InsertEdge(MGraph Graph, Edge E) {//插入边
Graph->G[E->V1][E->V2] = E->Weight;
Graph->G[E->V2][E->V1] = E->Weight;//若是无向图,还要插入边<V2,V1>
//若是有向图,可以把后一句去掉
}
MGraph BuildGraph() {//建立图
int Nv, Ne;
scanf("%d %d", &Nv, &Ne);//读入顶点个数和边数
MGraph Graph = CreateGraph(Nv, Ne);//初始化有Nv个顶点没有边的图
Edge E = (Edge)malloc(sizeof(struct ENode));//建立边结点
for (int i = 0; i < Ne; i++) {
scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
InsertEdge(Graph, E);
}
return Graph;
}
void Print(MGraph Graph) {//将整个图打印出来
for (int i = 0; i < Graph->Nv; i++) {
for (int j = 0; j < Graph->Nv; j++)
printf("%d ", Graph->G[i][j]);
printf("\n");
}
}
Vertex FindMinDist(MGraph Graph, WeightType dist[]) {
Vertex MinV, V;
WeightType MinDist = INFINITY;
for (V = 0; V < Graph->Nv; V++) {
if (dist[V] != 0 && dist[V] < MinDist) {
MinDist = dist[V];
MinV = V;
}
}
if (MinDist < INFINITY)return MinV;
else return -1;
}
int flag[100][100] = { 0 };//用数组flag来标记图中的边是否已经输出过
int Prim(MGraph Graph) {
WeightType dist[MaxVertexNum], TotalWeight = 0;
Vertex parent[MaxVertexNum], v, w;
int VCount = 0;//记录已经连接好的顶点数
Edge E = (Edge)malloc(sizeof(struct ENode));
for (v = 0; v < Graph->Nv; v++) {
dist[v] = Graph->G[0][v];
parent[v] = 0;
}
dist[0] = 0;
parent[0] = -1;
VCount++;
while (1) {
v = FindMinDist(Graph, dist);
if (v == -1) break;
E->V1 = parent[v];
E->V2 = v; E->Weight = dist[v];
if (flag[E->V1][E->V2] == 0) {
printf("%d %d\n", E->V1, E->V2);
flag[E->V1][E->V2] = 1;
}
TotalWeight += dist[v];//加上选择的边的权重
dist[v] = 0;
VCount++;
for (w = 0; w < Graph->Nv; w++) {
if (dist[w] != 0 && Graph->G[v][w] < INFINITY) {
if (Graph->G[v][w] < dist[w]) {
dist[w] = Graph->G[v][w];
parent[w] = v;
}
}
}
}
if (VCount < Graph->Nv)return -1;
return TotalWeight;
}
int main() {
MGraph g = BuildGraph();
if (Prim(g) != -1)printf("%d\n", Prim(g));
return 0;
}
运行结果
输出格式是先将选择的边输出,而后输出最小生成树的最小权值。
Kruskal算法
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct ENode {
int V1, V2;//两顶点
int Weight;//权值
}*Edge;
int n, m;//顶点数与边数
void Swap(Edge E[], int i, int j) {
Edge t = E[i];
E[i] = E[j];
E[j] = t;
}
void Sort(Edge E[]) {
for (int i = 0; i < m; i++) {
for (int j = i + 1; j < m; j++)
if (E[i]->Weight > E[j]->Weight) {
Swap(E, i, j);//交换
}
}
}
void Create(Edge E[]) {
scanf("%d %d", &n, &m);
for (int i = 0; i < m; i++)
E[i] = (Edge)malloc(sizeof(struct ENode));
for (int i = 0; i < m; i++)
scanf("%d %d %d", &E[i]->V1, &E[i]->V2, &E[i]->Weight);
}
int Find(int parent[], int i) {
while (parent[i] > 0)
i = parent[i];
return i;
}
void Kruskal(Edge E[]) {
Sort(E);
int TotalWeight = 0;
int visited[105][105] = { 0 }, parent[105] = { 0 };
for (int i = 0; i < m; i++) {
int x = Find(parent, E[i]->V1);
int y = Find(parent, E[i]->V2);
if (x != y) {
parent[x] = y;
printf("%d %d\n", E[i]->V1, E[i]->V2);
TotalWeight += E[i]->Weight;
}
}
printf("%d\n", TotalWeight);
}
int main() {
Edge E[105];
Create(E);
Kruskal(E);
return 0;
}
运行结果
输出格式和Prim的是一样的。
结语
可以看到,输入一样的数据,输出结果是不一样的,具体我就不说了。
因为刚刚放寒假回到家,我懒癌犯了。。。有点不想动,不想学习,正在尝试开始动脑。其实其他博主写的博客已经写的很好了,我也不太想重复这些东西,直接上源代码就好啦。