普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。
算法的描述:
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
网上实在没有找到好的图片于是自己画了一张,这个是《数据结构与算法分析-c语言描述》的图,画得比较抽象- -
边上的数字就是权值
实现这个图的算法
头文件:有权无向图的邻接表
#ifndef _adja2_h
#define _adja2_h
#define SIZE (7)
//定义节点数
#define EGDE (12)
//定义边数
struct Node;
typedef struct Node *PNode;
typedef struct Node
{
int x;
int quan;
PNode next;
}*EdgeNode;
typedef struct vertex
{
EdgeNode ele[SIZE];
}*List;
void Adja(List L)
{
EdgeNode S;
int i,j,k,m,v;
for(k=1;k<=SIZE;k++)
L->ele[k]=NULL;
for(v=0;v<EDGE;v++)
{
printf("please input information:");
scanf("%d%d",&i,&j);
printf("Input quan:");
scanf("%d",&m);
S=malloc(sizeof(struct Node));
S->x=j;
S->quan=m;
S->next=L->ele[i];
L->ele[i]=S;
S=malloc(sizeof(struct Node));
S->x=i;
S->quan=m;
S->next=L->ele[j];
L->ele[j]=S;
}
}
#endif
prim.c文件实现算法并验证
#include <stdio.h>
#include <stdlib.h>
#include "adja2.h"
#define NotAVertex (-1)
#define SIZE (7)
typedef struct TableEntry
{
int Known;
int Dist;
int Path;
}*Table;
//初始化T
void InitTable(Table T)
{
int i;
for(i=1;i<=SIZE;i++)
{
T[i].Known=0;
T[i].Dist=20;
T[i].Path=NotAVertex;
}
}
//主要函数,生成最小生成树
void Prim(Table *T)
{
int v;
int j,i,k,a;
int min;
List L;
L=malloc(sizeof(struct vertex));
Adja(L);
(*T)[1].Dist=0;
for(;;){
//令v等于Dist最小的未知顶点
a=1;
j=1;
//找出节点位置最小的未知节点
while((*T)[j].Known==1)
j++;
//令min等于节点位置最小的节点Dist
min=(*T)[j].Dist;
//找出最小的值min
for(i=j+1;i<=SIZE;i++)
if(!(*T)[i].Known)
if((*T)[i].Dist<min)
min=(*T)[i].Dist;
//从节点1开始令其Dist和min匹配,如果匹配到则说明k节点就是存储最小Dist的未知节点喽
for(k=1;k<=SIZE;k++){
if((*T)[k].Known==0&&(*T)[k].Dist==min){
v=k;
break;
}
}
//如果所有节点都已知,那么退出循环
while((*T)[a].Known==1){
a++;
}
if(a==SIZE+1)
break;
if(v==NotAVertex)
break;
(*T)[v].Known=1;
//所有与v相邻的未知节点求dw,dw=min(dw,cwv)
while(L->ele[v]!=NULL){
if(!(*T)[(L->ele[v]->x)].Known)
if((*T)[(L->ele[v]->x)].Dist>L->ele[v]->quan){
(*T)[(L->ele[v]->x)].Dist=L->ele[v]->quan;
(*T)[(L->ele[v]->x)].Path=v;
}
L->ele[v]=L->ele[v]->next;
}
}
}
int main()
{
Table T;
int i,s=0,j;
List L;
T=malloc(sizeof(struct TableEntry)*(SIZE+1));
InitTable(T);
Prim(&T);
//输出最小生成树
for(i=2;i<=SIZE;i++)
printf("%d-%d\t",i,T[i].Path);
//输出最小生成树的权的和
for(i=2;i<=SIZE;i++)
s+=T[i].Dist;
printf("%d\n", s);
return 0;
}
输出最小生成树的最短路径为16
每个顶点相连的点为2-1,3-4,4-1,5-7,6-7,7-4