最小生成树Prim算法

#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 100      //最大顶点数
typedef char VertexType;     //顶点
typedef int EdgeType;   //权值
#define INFINITY 65535      /*用65535来代表∞*/
#define UNVISITED -1    //标记未访问
#define VISITED 1   //标记未访问

//Dist的存储结构
typedef struct
{
    int index;  //顶点的索引值
    int length; //当前最短路径长度
    int pre;    //路径最后经过的顶点
}Dist;

typedef struct
{
    int from;   //边的始点
    int to; //边的终点
    EdgeType weight;    //权重
}Edge;  //边的结构

//图的结构
typedef struct
{
    int numVertex;  //顶点个数
    int numEdge;    //边的个数
    VertexType vexs[MAXVEX];    /*顶点表*/
    int Indegree[MAXVEX];   //顶点入度
    int Mark[MAXVEX];   //标记是否被访问过
    EdgeType arc[MAXVEX][MAXVEX];   //边表
    Dist D[MAXVEX];
    Edge MST[MAXVEX];   //数组MST用于保存最小生成树的边
}Graph;



//初始化图(初始化Mark数组,D数组)
void InitGraph(Graph * G,int s,int numVert,int numEd )  //传入顶点个数,边数,s为源点
{
    G->numVertex=numVert;
    G->numEdge=numEd;
    for(int i=0;i<numVert;i++)
    {
        G->Mark[i]=UNVISITED;
        G->D[i].index=i;
        G->D[i].length=INFINITY;
        G->D[i].pre=s;
        G->Indegree[i]=0;
        for(int j=0;j<numVert;j++)
        {
            G->arc[i][j]=INFINITY;
            if(i==j)
            {
                G->arc[i][j]=0;
            }
        }
    }
    G->D[s].length=0;
    G->Mark[s]=VISITED; //开始源点标记为VISITED
    return ;
}


//判断是否为边
bool IsEdge(Edge oneEdge)
{
    if(oneEdge.weight>0 && oneEdge.weight!=INFINITY && oneEdge.to>=0)
    {
        return true;
    }
    else
    {
        return false;
    }
}



//建立无向图的邻接矩阵
void CreatGraph(Graph * G)
{
    int i,j,k,w;
    printf("请输入%d个顶点元素:\n",G->numVertex);
    for(i=0;i<G->numVertex;i++)
    {
        scanf(" %c",&G->vexs[i]);
    }
    for(k=0;k<G->numEdge;k++)
    {
        printf("请输入边(Vi,Vj)的下标Vi,Vj,和权重w:\n");
        scanf("%d%d%d",&i,&j,&w);
        G->Indegree[i]++;
        G->Indegree[j]++;
        G->arc[i][j]=w;
        G->arc[j][i]=G->arc[i][j];
    }
}




//返回顶点个数
int VerticesNum(Graph * G)
{
    return G->numVertex;
}


//返回依附于顶点的第一条边
Edge FirstEdge(Graph * G,int oneVertex)
{
    Edge firstEdge;
    firstEdge.from=oneVertex;
    for(int i=0;i<G->numVertex;i++)
    {
        if(G->arc[oneVertex][i]!=0 && G->arc[oneVertex][i]!=INFINITY)
        {
            firstEdge.to=i;
            firstEdge.weight=G->arc[oneVertex][i];
            break;
        }

    }
    return firstEdge;
}   


//返回oneEdge的终点
int ToVertex(Edge oneEdge)
{
    return oneEdge.to;
}


//返回与preEdge有相同顶点的下一条边
Edge NextEdge(Graph * G,Edge preEdge)
{
    Edge myEdge;
    myEdge.from=preEdge.from;   //边的始点与preEdge的始点相同
    if(preEdge.to<G->numVertex) //如果preEdge.to+1>=G->numVertex;将不存在下一条边
        for(int i=preEdge.to+1;i<G->numVertex;i++)  //找下一个arc[oneVertex][i]
        {                                           //不为0的i
            if(G->arc[preEdge.from][i]!=0 && G->arc[preEdge.from][i]!=INFINITY)
            {
                myEdge.to=i;
                myEdge.weight=G->arc[preEdge.from][i];
                break;
            }
        }
        return myEdge;
}



int minVertex(Graph * G)
{
    int i,v;
    for(i=0;i<G->numVertex;i++)
    {
        if(G->Mark[i]==UNVISITED)
        {
            v=i;
            break;
        }
    }
    for(i=0;i<G->numVertex;i++)
    {
        if(G->Mark[i]==UNVISITED && (G->D[i].length<G->D[v].length))
        {
            v=i;
        }
    }
    return v;
}

//设置一条边
Edge Setedge(int from,int to,int weight)
{
    Edge edge;
    edge.from=from;
    edge.to=to;
    edge.weight=weight;
    return edge;
}

void Edge_to_MST(Graph * G,Edge e,int num)
{
    G->MST[num]=e;
}



//打印出MST数组
void Print_MST(Graph * G,int n)
{
    for(int i=0;i<n;i++)
    {
        printf("elem:%c->%c   Edge:(%d,%d)  length:%d\n",G->vexs[G->MST[i].from],G->vexs[G->MST[i].to],G->MST[i].from,G->MST[i].to,G->MST[i].weight);
    }
    printf("\n");
}


void Prim(Graph * G,int s)
{
    int MSTtag=0;   //最小生成树的边计数
    int v=s;    //保存源点
    for(int i=0;i<G->numVertex-1;i++)
    {
        if(G->D[v].length==INFINITY)    //非连通,有不可到达的点
            return ;
        //因为v的加入,需要刷新与v相等邻接的顶点的D值
        for(Edge e=FirstEdge(G,v);IsEdge(e);e=NextEdge(G,e))
        {
            if(G->Mark[ToVertex(e)]!=VISITED && G->D[ToVertex(e)].length>e.weight)
            {
                G->D[ToVertex(e)].length=e.weight;
                G->D[ToVertex(e)].pre=v;
            }
        }
            v=minVertex(G);     //找出最小的边
            G->Mark[v]=VISITED;
            Edge edge=Setedge(G->D[v].pre,G->D[v].index,G->D[v].length);
            Edge_to_MST(G,edge,MSTtag++);   //最小生成树的边数+1
    }
    Print_MST(G,MSTtag);    //输出结果
}




int main()
{
    Graph G;
    int numVert,numEd;
    printf("请输入顶点数和边数:\n");
    scanf("%d%d",&numVert,&numEd);
    InitGraph(&G,0,numVert,numEd ); //设置0为源点
    CreatGraph(&G);
    Prim(&G,0); //设置0为源点
    return 0;
}

这里写图片描述这里写图片描述
这里写图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值