普里姆算法(邻接矩阵)
思想
从某个顶点开始(不要把它看成一个单独的顶点,把它看成只有一个结点的子生成树)
在第一步的生成树的相邻边中,选一条最小的边,将最小的边和边的另一个结点并入子生成树中(生成树就长大了一点)
继续,直到所有的顶点都被并入了生成树
步骤
1.取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w
2.在添加的顶点 w 和已经在生成树上的顶点v 之间必定存在一条边,
3.并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。
4.之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。
性能
O(n^2),适合稠密图(边多的图)
另一个【克鲁斯卡尔算法】O(eloge):适合稀疏图(边少的图)
举例
1.蓝色的顶点:还未考虑的顶点
2.黄色的顶点:已经考虑完的顶点
3.蓝色的线:未考虑的边
4.紫色的线:考虑范围内的边
5.红色的线:生成树的边(最短的边)
将a纳入考虑的顶点,变成黄色
第一步:考虑黄色顶点【a】
1.考虑与a相连的所有边(紫色的边),取出最短的边:18
2.将最短边,纳入生成树的边(变红色)
3.将顶点b纳入已考虑的顶点(变黄色)
第二步:考虑黄色的顶点【a,b】
1.考虑与a,b相连的所有边(紫色的边),取出最短的边8
2.将最短边,纳入生成树的边(变红色)
3.将顶点c纳入已考虑的顶点(变黄色)
第三步:继续考虑黄色的顶点【a,b,c】
1.考虑与a,b,c相连的所有边(紫色的边),取出最短的边20
2.将最短边,纳入生成树的边(变红色)
3.将顶点d纳入已考虑的顶点(变黄色)
最终
实现
记:
1.黄色的顶点,为顶点集【U】,即已落在生成树上的顶点
2.蓝色的顶点,为顶点集【V-U】,即尚未落在生成树上的顶点
设置一个辅助数组
1.下标:顶点v
2.lowcost:记录【黄色的点们】到【v】的最短边
3.adjvex:记录【黄色的点集】中哪一个顶点,到v最短
最小生成树
void Prim(MGraph* mgraph, int v)
{
int i, j;
int min, index;
int lowcost[NUM]; //记录当前树到剩余节点的最小权值 lowcost[i] = 0 表示i在树中
int adjvex[NUM] = { 0 }; //保存邻接节点下标数组
adjvex[1] = 1;
lowcost[1] = 0;
for (i = 2;i <= mgraph->vexnum;i++)
{
lowcost[i] = mgraph->arcs[v][i]; //将与下标为0的顶点有边的权值存入lowcost数组中
adjvex[i] = 1; //这些顶点的adjvex数组全部初始化为0
}
for (j = 2;j <= mgraph->vexnum;j++)
{
min = INT_MAX; //需要找最小值设置一个最大值比较
index = 1;
for (i = 1;i <= mgraph->vexnum;i++)
{
if (lowcost[i] != 0 && lowcost[i] != MAX_NUM)
{
if (lowcost[i] < min)
{
min = lowcost[i];
index = i;
}
}
}
printf("%c -> %c :%d\n", mgraph->vexs[adjvex[index]], mgraph->vexs[index], min);
lowcost[index] = 0; //将该顶点加入到生成树中
for (i = 1;i <= mgraph->vexnum;i++)
{
if (mgraph->arcs[i][index] < lowcost[i] &&lowcost[i] != 0)
{
lowcost[i] = mgraph->arcs[index][i];
adjvex[i] = index;
}
}
}
}
完整代码
#include<stdio.h>
#include<stdlib.h>
#define MAX_VEX_NUM 20 //最大顶点数
#define MAX_NUM (int)1000
typedef char VertextType;
typedef enum { DG, UDG }GraphKind; //判定图的类型,有向或无向
typedef struct
{
VertextType vexs[MAX_VEX_NUM]; //存放结点的char行数组
int arcs[MAX_VEX_NUM][MAX_VEX_NUM]; //存放边的数组
int vexnum, arcnum;//结点数,边数
GraphKind Type;//存放图的类型
}MGraph;
//索引判断
int index(char vex, MGraph* mg)
{
int i;
for (i = 1;i <= mg->vexnum;i++)
{
if (mg->vexs[i] == vex)
return i;
}
return 0;
}
//生成邻接矩阵
void Creat_MG(MGraph* mg)
{
int type, i, j, k, v1_index, v2_index ,weight = 0;
char v1, v2;
printf("please input graph type 0.DG 1.UDG. input nums:");
scanf_s("%d", &type); //输入图的类型
if (type == 0)
mg->Type = DG;
else if (type == 1)
{
mg->Type = UDG;
}
else
{
printf("please input 0 or 1!!!");
return;
}
printf("Please input vexnum:");
scanf_s("%d", &mg->vexnum); //输入结点数
printf("Please input arcnum:");
scanf_s("%d", &mg->arcnum);//输入边数
getchar();
for (i = 1;i <= mg->vexnum;i++)
{
printf("please input %d vex:", i);
scanf_s("%c", &mg->vexs[i], 1);//循环存放每个结点
getchar();
}
for (i = 1;i <= mg->vexnum;i++)
for (j = 1;j <= mg->vexnum;j++)
mg->arcs[i][j] = MAX_NUM;//初始化边,全部设为MAX_NUM
for (i = 1;i <= mg->vexnum;i++)
mg->arcs[i][i] = 0;//初始化边,全部设为0
for (k = 1;k <= mg->arcnum;k++)
{
printf("Please input %d arc(vex1,vex2):", k);
scanf_s("%c %c %d", &v1, 1, &v2, 1, &weight);
v1_index = index(v1, mg);//索引该结点对应的位置
v2_index = index(v2, mg);//索引该结点对应的位置
if (mg->Type == 1)//如果是无向图
{
mg->arcs[v1_index][v2_index] = weight;
mg->arcs[v2_index][v1_index] = weight;//将矩阵的对应的值1
}
else
mg->arcs[v1_index][v2_index] = weight;
getchar();
}
}
void Print_MG(MGraph* mg)
{
int i, j;
if (mg->Type == 0)
printf("Is Direct Graph\n");
else
printf("Is UNDirect Graph\n");
for (i = 1;i <= mg->vexnum;i++)
{
for (j = 1;j <= mg->vexnum;j++)
{
if (mg->arcs[i][j] == MAX_NUM)
{
printf("∞ ");
}
else
{
printf("%-4d", mg->arcs[i][j]);//遍历输出矩阵
}
}
printf("\n");
}
}
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "MGraph.h"
#define NUM 30
#define MAX_NUM (int)1000
void Prim(MGraph* mgraph, int v)
{
int i, j;
int min, index;
int lowcost[NUM]; //记录当前树到剩余节点的最小权值 lowcost[i] = 0 表示i在树中
int adjvex[NUM] = { 0 }; //保存邻接节点下标数组
adjvex[1] = 1;
lowcost[1] = 0;
for (i = 2;i <= mgraph->vexnum;i++)
{
lowcost[i] = mgraph->arcs[v][i]; //将与下标为0的顶点有边的权值存入lowcost数组中
adjvex[i] = 1; //这些顶点的adjvex数组全部初始化为0
}
for (j = 2;j <= mgraph->vexnum;j++)
{
min = INT_MAX; //需要找最小值设置一个最大值比较
index = 1;
for (i = 1;i <= mgraph->vexnum;i++)
{
if (lowcost[i] != 0 && lowcost[i] != MAX_NUM)
{
if (lowcost[i] < min)
{
min = lowcost[i];
index = i;
}
}
}
printf("%c -> %c :%d\n", mgraph->vexs[adjvex[index]], mgraph->vexs[index], min);
lowcost[index] = 0; //将该顶点加入到生成树中
for (i = 1;i <= mgraph->vexnum;i++)
{
if (mgraph->arcs[i][index] < lowcost[i] &&lowcost[i] != 0)
{
lowcost[i] = mgraph->arcs[index][i];
adjvex[i] = index;
}
}
}
}
int main()
{
MGraph MG;
Creat_MG(&MG);
Print_MG(&MG);
Prim(&MG, 1);
return 0;
}