c语言实现普利姆算法
以王卓老师讲的思路编写的c语言版的普利姆算法
如图,先构建一个图G,输入顶点数,边数,边的名字,这里我用a~f来命名,再输入边的权值,先输入边的两个顶点,再输入对应的权值,在将所有的边输入完毕后,就构建好了图G,下面会输出图G的邻接矩阵和图G的最小生成树的邻接矩阵,注意调用构建最小生成树函数的时候要指明从哪个结点开始。 作者:Wanna_雄 https://www.bilibili.com/read/cv16003601 出处:bilibili
下面示例使用的图G
1.构建图G,分别输入结点数,边数,结点名称,权值。
2.图的邻接矩阵
3.生成树的邻接矩阵
代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxsize 100
typedef char vertextype; //定义结点类型
typedef int arctype; //定义边类型
typedef struct{ //定义邻接矩阵的结构体
vertextype vexs[maxsize];
arctype arcs[maxsize][maxsize];
int vexnum,arcnum;
}Amgraph;
typedef struct{ //定义最小生成树的结构体
int vexnum1;
int arcnum1;
int TE[maxsize][maxsize];
}LTgraph;
int locatevex(Amgraph G,char v){ //返回结点v的数组下标
int m=0;
for(m=0;m<G.vexnum && G.vexs[m]!=v;m++);
printf("the location is %d\n",m);
return m;
}
void creatudn(Amgraph &G){ //创建图,初始化图
for(int i=0;i<maxsize;i++){ //初始化邻接矩阵全为0;
for(int j=0;j<maxsize;j++){
G.arcs[i][j]=0;
}
}
printf("please enter the vexnum:"); //输入结点数
scanf("%d",&G.vexnum);
printf("\n");
printf("please enter the arcnum:"); //输入边数
scanf("%d",&G.arcnum);
printf("\n");
for(int i=0;i<G.vexnum;i++){ //输入结点名称
printf("please enten the %d's vex",i);
scanf("%s",&G.vexs[i]);
printf("\n");
}
for(int i=0;i<G.vexnum;i++){
for(int j=0;j<G.vexnum;j++){
G.arcs[i][j]=0;
}
}
for(int k=0;k<G.arcnum;k++){ //输入权值,格式为(V1,V2,Weight) ;
char v1;
char v2;
int w;
printf("please enter vex1:");
char c=getchar();
scanf("%c",&v1);
printf("the v1 is %c\n",v1);
printf("please enter vex2:");
char d=getchar();
scanf("%c",&v2);
printf("the v2 is %c\n",v2);
printf("\n");
printf("please enter the weight:");
scanf("%d",&w);
printf("\n");
int i = locatevex(G,v1);
//printf("%d",i);
int j = locatevex(G,v2);
//printf("%d",j);
G.arcs[i][j] = w;
G.arcs[j][i] = G.arcs[i][j];
//printf()
}
}
void DFS(Amgraph G,int v,int visit[ ]){ //深度优先遍历图
printf("%c\t",G.vexs[v]);
//int visit[G.vexnum];
visit[v]=1;
int w=0;
for(w=0;w<G.vexnum;w++){
if(G.arcs[v][w]!=0 && visit[w]!=1){
DFS(G,w,visit);
}
}
}
void WFS(Amgraph G,int v,int visit[ ],int lun[ ]){ //广度优先遍历图
if(visit[v]!=1){
printf("%c\t",G.vexs[v]);
visit[v]=1;
}
//printf("%c",G.vexs[v]);
for(int w=0;w<G.vexnum;w++){
if(G.arcs[v][w]!=0 && visit[w]!=1){
printf("%c\t",G.vexs[w]);
visit[w]=1;
}
}
lun[v]=1;
for(int w=0;w<G.vexnum;w++){
if(G.arcs[v][w]!=0 && lun[w]!=1){
WFS(G,w,visit,lun);
}
}
}
int findleastarc(LTgraph <,Amgraph G,int u[ ],int v[ ]){
//printf("has in the find") ;
int w=0,m=0; //用于记录找到最小权值时的数组下标
int least=maxsize; //暂存最小权值
for(int i=0;i<LT.vexnum1;i++){ //遍历图G的邻接矩阵,在u集合上的点的邻接点中权值最小的,加入集合u中,把边加入TE矩阵中
if(u[i]==1){
for(int j=0;j<LT.vexnum1;j++){
if(G.arcs[i][j]!=0 && u[j]==0){
if(G.arcs[i][j]<least){
least=G.arcs[i][j];
w=j;
m=i;
}
}
}
}
}
LT.TE[m][w]=G.arcs[m][w]; //TE为一邻接矩阵 用来表示最小生成树,这里w和m表示找到的权值最小的边的尾结点的下标
LT.TE[w][m]=LT.TE[m][w];
u[w]=1; //对U和V进行修改,来达到增加和删除的操作
v[w]=0;
int i=0;
for(i=0;i<LT.vexnum1 && u[i]==1;i++); //查看U中是否包含所有的结点
if(i<LT.vexnum1){
printf("i=%d\n",i);
findleastarc(LT,G,u,v);
}
return 1;
}
void prime(Amgraph G,LTgraph <,int v){ //普利姆算法构建最小生成树
// printf("has in");
int U[G.vexnum]; //定义数组u来存放已经找到的结点
int V[G.vexnum]; //v来存储u之外的结点
for(int i=0;i<LT.arcnum1;i++){ //初始化,用TE来表示最小生成树的邻接矩阵
for(int j=0;j<LT.arcnum1;j++){
LT.TE[i][j]=0;
}
}
for(int i=0;i<LT.vexnum1;i++){ //初始化u,V数组
U[i]=0;
V[i]=1;
}
U[v]=1;
V[v]=0;
printf("has in");
findleastarc(LT,G,U,V);
/*普利姆算法过程,从v结点开始,置结点U【v】 为1,V【v】 为0,
查找U 数组上为1的节点,即已经找过的节点,遍历这些结点的邻接点,
找到其中权值最小的边,将边尾结点加入U数组中,v数组剔除掉他,再递归调用该函数,直到u数组中包含所有的结点
*/
}
int main(){
Amgraph G; //定义图G
LTgraph LT; //定义生成树LT
creatudn(G); //构建图G
LT.vexnum1 = G.vexnum; //生成树的结点数=图的结点数
LT.arcnum1=LT.vexnum1-1;
for(int i=0;i<G.vexnum;i++) { //输出图G的邻接矩阵
for(int j=0;j<G.vexnum;j++){
printf("%d ",G.arcs[i][j]);
}
printf("\n");
}
printf("\n");
prime(G,LT,0); //普利姆算法构建最小生成树
//printf("prime has done");
int visit[G.vexnum]; //这个时深度广度遍历中记录结点是否被遍历过的数组
int visit1[G.vexnum];
int lun[G.vexnum];
for(int i=0;i<G.vexnum;i++) { //输出最小生成树的邻接矩阵
for(int j=0;j<G.vexnum;j++){
printf("%d ",LT.TE[i][j]);
}
printf("\n");
}
//DFS(G,0,visit);
//printf("\n");
//WFS(G,0,visit1,lun);
return 0;
}