最小生成树的普利姆算法和克鲁斯卡尔算法
最小生成树的概念:指含有图中全部顶点的极小连通子树,包含所有顶点n,但只有足以构成一棵树的n-1条边
求最小生成树可以采用普利姆算法和克鲁斯卡尔算法
以下图为例

先构造带权图
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define MAX 0x7fffffff
typedef char VertexType;
typedef int EdgeType;
typedef struct
{
//顶点数组
VertexType vertex[MAXSIZE];
//边的二维数组
EdgeType arc[MAXSIZE][MAXSIZE];
int Vertex_num;
int Edge_num;
}Mat_graph;
int visit[MAXSIZE];
//构建带权图
void creat_graph(Mat_graph* G)
{
G->Vertex_num = 9;
G->Edge_num = 15;
G->vertex[0] = 'A';
G->vertex[1] = 'B';
G->vertex[2] = 'C';
G->vertex[3] = 'D';
G->vertex[4] = 'E';
G->vertex[5] = 'F';
G->vertex[6] = 'G';
G->vertex[7] = 'H';
G->vertex[8] = 'I';
for (int i = 0;i < G->Vertex_num;i++)
{
for (int j = 0;j < G->Vertex_num;j++)
{
if (i == j)
{
G->arc[i][j] = 0;
}
else
{
G->arc[i][j] = MAX;
}
}
}
G->arc[0][1] = 10;
G->arc[0][5] = 11;
G->arc[1][2] = 18;
G->arc[1][6] = 16;
G->arc[1][8] = 12;
G->arc[2][3] = 22;
G->arc[2][8] = 8;
G->arc[3][4] = 20;
G->arc[3][6] = 24;
G->arc[3][7] = 16;
G->arc[3][8] = 21;
G->arc[4][5] = 26;
G->arc[4][7] = 7;
G->arc[5][6] = 17;
G->arc[6][7] = 19;
for (int i = 0;i < G->Vertex_num;i++)
{
for (int j = 0;j < G->Vertex_num;j++)
{
G->arc[j][i] = G->arc[i][j];
}
}
}
普利姆算法
普利姆算法:从一个顶点开始,每次比较待选的所有路径,并选择最小的路径,直到每个顶点都遍历一遍
代码实现
//普利姆算法
void prim(Mat_graph* G)
{
int i, j, k;
int min;
//待比较的权值
int weight[MAXSIZE];
//记录边,数组中的值表示出发点,数组下标表示到达点
int index[MAXSIZE];
for (i = 0;i < G->Vertex_num;i++)
{
weight[i] = G->arc[0][i];
index[i] = 0;
}
for (int i = 1;i < G->Vertex_num;i++)
{
min = MAX;
j = 0;
k = 0;
while (j < G->Vertex_num)
{
if (weight[j] != 0 && weight[j] < min)
{
min = weight[j];
k = j;
}
j++;
}
printf("(%c,%c)\n", G->vertex[index[k]], G->vertex[k]);
weight[k] = 0;
//比较新的结点的权值,并把边记录下去
for (int j = 0;j < G->Vertex_num;j++)
{
if (weight[j] != 0 && G->arc[k][j] < weight[j])
{
weight[j] = G->arc[k][j];
index[j] = k;
}
}
}
}
主函数
int main()
{
Mat_graph G;
creat_graph(&G);
prim(&G);
printf("\n");
return 0;
}

克鲁斯卡尔算法
克鲁斯卡尔算法是对边进行操作,先找权值最小的边,在依次选择,但要注意避免形成回路
代码如下
其中构造带权图的代码和上面一样
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
#define MAX 0x7fffffff
typedef char VertexType;
typedef int EdgeType;
typedef struct
{
//顶点数组
VertexType vertex[MAXSIZE];
//边的二维数组
EdgeType arc[MAXSIZE][MAXSIZE];
int Vertex_num;
int Edge_num;
}Mat_graph;
//边的存储
typedef struct
{
int begine;
int end;
int weight;
}Edge;
//交换
void swap(Edge* a, Edge* b)
{
Edge temp;
temp = *a;
*a = *b;
*b = temp;
}
//将边数组从小到大进行排序
void sortEdge(Edge edgh[], int edge_num)
{
for (int i = 0;i < edge_num;i++)
{
for (int j = i + 1;j < edge_num;j++)
{
if (edgh[i].weight > edgh[j].weight)
{
swap(&edgh[i], &edgh[j]);
}
}
}
}
//避免形成回路
int find(int* parent, int index)
{
while (parent[index] > 0)
{
index = parent[index];
}
return index;
}
//克鲁斯卡尔算法
void Kruskal(Mat_graph* G)
{
Edge edgh[MAXSIZE];
int k = 0;
for (int i = 0;i < G->Vertex_num;i++)
{
for (int j = i+1;j < G->Vertex_num;j++)
{
if (G->arc[i][j] < MAX)
{
edgh[k].begine = i;
edgh[k].end = j;
edgh[k].weight = G->arc[i][j];
k++;
}
}
}
sortEdge(&edgh, G->Edge_num);
int parent[MAXSIZE];
for (int i = 0;i < G->Vertex_num;i++)
{
parent[i] = 0;
}
int m, n;
for (int i = 0;i < G->Edge_num;i++)
{
m = find(parent, edgh[i].begine);
n = find(parent, edgh[i].end);
if (m != n)
{
parent[m] = n;
printf("(%c,%c) %d\n", G->vertex[edgh[i].begine], G->vertex[edgh[i].end], edgh[i].weight);
}
}
}
主函数
int main()
{
Mat_graph G;
creat_graph(&G);
Kruskal(&G);
printf("\n");
return 0;
}

在最小生成树中,库鲁斯卡尔算法针对边进行操作,适合边数少的情况。而普里斯算法针对顶点,适用于边数多的情况
330

被折叠的 条评论
为什么被折叠?



