数据结构-最小生成树-普里姆算法
转自https://blog.csdn.net/ZGUIZ/article/details/54633115
首先仍然是预定义:
1 #define OK 1 2 #define ERROR 0 3 #define Max_Int 32767 4 #define MVNum 100 5 6 typedef int Status; 7 typedef char VerTexType; 8 typedef int ArcType; 9 10 struct{ 11 VerTexType adjvex; //前一个顶点 12 ArcType lowcost; //最近距离大小 初始化时为权值 13 }closedge[MVNum]; 14 15 typedef struct{//图的结构体 存储结构是邻接矩阵 16 VerTexType vex[MVNum]; //顶点信息 17 ArcType arc[MVNum][MVNum]; //邻接矩阵 18 int vexnum, arcnum; //顶点数 边数 19 }AMGraph;
结构体数组closedge[]用于记录与下标节点最小权值边的值以及权值(即最小权值)。
创建图:
int LocateVex(AMGraph *G,VerTexType v) { //找到下标 int i; for (i = 0; i < G->vexnum; i++) { if (G->vex[i] == v) return i; } return -1; } Status CreateUDN(AMGraph *G) { int i, j, k; VerTexType v1, v2; ArcType w; printf("输入总节点数和总边数:"); scanf("%d %d", &G->vexnum, &G->arcnum); fflush(stdin); printf("输入各个节点的值:"); for (i = 0; i < G->vexnum; i++) scanf("%c", &G->vex[i]); for (i = 0; i < G->vexnum;i++) for (j = 0; j < G->vexnum; j++) { G->arc[i][j] = Max_Int; } for (k = 0; k < G->arcnum; k++) { printf("输入一条边的两个顶点以及该边的权值:"); scanf("%c %c %d", &v1, &v2, &w); //他这个 输入的是顶点信息 通过LOCATEVEX函数找到对应的下标 再更新邻接矩阵 i = LocateVex(G, v1); j = LocateVex(G, v2); G->arc[i][j] = w; G->arc[j][i] = G->arc[i][j]; } return OK; }
查找下一个权值最小的边上的另一个节点:
int Min(AMGraph G) { int i; int min = Max_Int; int index = -1; for (i = 0; i < G.vexnum; i++) { if (min>closedge[i].lowcost&&closedge[i].lowcost!=0) { min = closedge[i].lowcost; index = i; } } return index; }
开始时让min为最大值,index用于记录最小值的下标,开始时设为-1。将closedge[]数组中lowcost(最小权值)与min进行比较,若有比min小的,则将其值赋值给min,并用index记录下标,重复比较,选出最小边。返回index。
///////////////////////////////主
void MinSpanTree_Prim(AMGraph G, VerTexType v)//从顶点V出发 按照普里姆算法构建最小生成树 并输出每条边 和 总权值 { int i, j, k;
int sumlength=0;//总权值 VerTexType u0, v0; k = LocateVex(&G, v);//对应的下标 for (j = 0; j < G.vexnum; j++) { if (j != k) { closedge[j].adjvex = v; //对其他顶点的初始化 closedge[j].lowcost = G.arc[k][j]; } } closedge[k].lowcost = 0;//初始化自身 for (i = 1; i < G.vexnum; i++) { k = Min(G); u0 = G.vex[k]; v0 = closedge[k].adjvex; printf("%c->%c\n", v0, u0);//找到了一个
sumlength+=在这里更新; closedge[k].lowcost = 0;
for (j = 0; j < G.vexnum; j++) { //更新 if (closedge[j].lowcost>G.arc[k][j]) { closedge[j].adjvex = G.vex[k]; closedge[j].lowcost = G.arc[k][j]; } } }
cout<<sumlength<<endl; }
其中,v为开始的节点。先确定v的下标,并将closedge[]数组初始化:将其记录的节点全部记录为v节点,并记录各个节点与其之间的权值。将closedge[]中v的权值记录为0,表示已经在已经遍历的数组中。
接下来用Min()函数确定最小权值的边的另一个节点下标k,由于closedge[]数组中k下标的元素记录了与其最短权值的边的第一节点,故只需输出closedge[k].adjvex和G.vex[k]。继续查找一个顶点在遍历数组中而且另一个顶点不再遍历数组中的最短边:在for()循环中,如果j下标的lowcost值大于图中k和j节点的权值,表明其不是最小权值边,则将closedge下标为j的元素中的节点值赋值为图中k下标的节点,并将其lowcost改为k和j的权值。
重复上面操作,得到最小生成树。
加入main():
int main(void) { AMGraph G; CreateUDN(&G); MinSpanTree_Prim(G, '1'); printf("\n"); return 0; }