最小生成树简述:
最小生成树(Minimum Spanning Tree)指,在一个有权图中寻找最小权值和的树来连通所有顶点。
Prim算法简述及准备:
Prim的思路很简单,设定一个初始点(列如V0),寻找从此连接的最小的权值的边,然后开始一起比较下一个点出去的所有边的权值,最终得到最小权值的连通所有点的边的最小生成树。
需要一个邻接矩阵表示的图来用于算法的实现:
typedef char VertexType; //顶点类型 ,默认为char
typedef int EdgeType; //边的权值 默认int
#define MAXVERTEX 10 //最大的顶点数 默认为10
#define INFINITY 65535 //表示无尽∞
//邻接矩阵的结构
struct MGraph
{
VertexType vexs[MAXVERTEX]; //顶点数组
EdgeType arc[MAXVERTEX][MAXVERTEX]; //邻接矩阵 即边数组
int vertexNum; //顶点数
int edgeNum; //边数
};
Prim最小生成树:
C++实现:
//Prim最小生成树
void PrimMinSpanTree(MGraph G)
{
int i, j, k; //i,j用于循环,k用于存储找到的最小权值顶点下标
int min; //min用于存储最小权值来进行比较
//初始化用于存储的数组
int adjVertex[MAXVERTEX]; //AdjVertex数组存储边的邻接点
int lowWeight[MAXVERTEX]; //lowWeight数组存储低权值边
lowWeight[0] = 0; //把lowWeight的0下标值设为0,表示0下标顶点V0已经在最小生成树中
adjVertex[0] = 0;
for (i = 1; i < G.vertexNum; i++) //从V1开始遍历,遍历邻接矩阵的第一行,即V0到与其相连的边的权值
{
lowWeight[i] = G.arc[0][i]; //把有权值的放入lowWeight数组,没有权值的默认为INFINITY
adjVertex[i] = 0; //把adjVertex数组都初始化为0
}
//最小生成树
for (i = 1; i < G.vertexNum; i++)
{
min = INFINITY; //先把min设为一个不可能的值
j = 1; k = 0;
while (j<G.vertexNum) //循环遍历lowWeight
{
if (lowWeight[j] !=0 && lowWeight[j]<min) //lowWeight为0表示该点已经在最小生成树中
{
//寻找lowWeight数组最小的值,并记录下标
min = lowWeight[j];
k = j;
}
j++;
}
//寻找到最小的权值边,开始打印
cout << "(" << adjVertex[k] << "," << k << ")" << endl; //输出找到的边
lowWeight[k] = 0; //把lowWeight找到的点的下标值设为0,不再参与后面循环
//改变lowWeight数组,将邻接矩阵第二行的值按条件放入数组用于下次循环
for (j = 1; j < G.vertexNum; j++)
{
if (lowWeight[j] != 0 && G.arc[k][j]<lowWeight[j])
{
lowWeight[j] = G.arc[k][j]; //把邻接矩阵第二行更小的数放入lowWeight数组,已经在树内的数除外
adjVertex[j] = k; //存储邻接点
}
}
}
}
Prim算法主要是嵌套循环,所以其时间复杂度为O(n^2)。
Kruskal算法简述及准备:
Kruskal算法不再从某一个顶点开始不断遍历寻找,而是优先找较小的权值,然后从最小权值的边进行构造最小生成树。
需要一个图的边集数组来进行
//边集数组结构
struct GraphEdge
{
VertexType begin;
VertexType end;
int weight;
};
Kruskal算法:
int Find(int *parent,int e);
//Kruskal最小生成树
void KruskalMinSpanTree(MGraph G)
{
int i; //用于遍历
int n, m; //用于判断
GraphEdge edges[MAXVERTEX]; //边集数组 按从小到大排列
int parent[MAXVERTEX]; //parent用于判断边是否形成了回路
for (i = 0; i < G.vertexNum; i++)
{
parent[i] = 0; //初始化parent数组全部为0
}
//遍历每一条边
for (i = 0; i < G.vertexNum; i++)
{
n = Find(parent, edges[i].begin);
m = Find(parent, edges[i].end);
if (n!=m) //n != m 说明没有形成闭合回路
{
parent[n] = m;
cout << "(" << edges[i].begin << "," << edges[i].end << ")" << edges[i].weight<<endl;
}
}
}
int Find(int *parent, int e)
{
while (parent[e]>0)
{
e = parent[e];
}
return e;
}