最小生成树PRIM算法

什么是最小生成树,请大家看看离散数学书.
自定义结构体

#define Max 100
#define MaxNode 10
typedef char VexType;
typedef int AdjType;
typedef struct{
    int n;
    VexType vexs[MaxNode];//保存节点
    AdjType arcs[MaxNode][MaxNode];//从矩阵获得节点与节点间的距离
}GraphMatrix;
typedef struct{
    int start_vex,stop_vex;//起点和终点
    AdjType weight;//边的权值
}Edge;

arcs[][]二维数组用来存储节点与节点之间的距离
Edge用来记录变得结构体,一条边有开始节点和停止节点,以及这条边的权值。
程序读取矩阵
首先,节点与节点之间的距离即边的权值用一个矩阵表示比较方便。我们可以把一个矩阵卸载一个txt文档里,再用程序读取,存在数组里。
下图就是存在txt文档里的矩阵
最小生成树PRIM算法_第1张图片
来看一下代码

void CreateGraph(GraphMatrix *G,int n)
{
    int i,j,k=1;
    FILE *fp;
    G->n = n;
    for(i=0;i//顶点赋初值
    {
        G->vexs[i] = (char)i;//节点名字0,1,2......以字符型保存.
    }
    if((fp = fopen("zrxprim.txt","r"))==NULL)
    {
        printf("can not open file\n");
    }
    for(i=0;i//边赋初值
    {
        for(j=0;jfscanf(fp,"%d",&G->arcs[i][j]);//将矩阵赋值到边的二维数组中
        }
    }
    if(fclose(fp))
    {
        printf("can not close the file\n");
    }
    for(i=0;ifor(j=0;jprintf("%6d ",G->arcs[i][j]);//输出图的矩阵
        }
        printf("\n");
    }
    printf("有向图的存储结构建立完毕!\n");
}

这里用fscanf来读取txt里的整数,可见fscanf遇到空格会自动跳过,遇到一行下次读取时,也会自动转到下一行,读取整数。
当然你要实现知道自己的矩阵几行几列。读取完成后再把整个矩阵输出
prim算法

void prim(GraphMatrix *graph,Edge *mst)
{
    int i,j,min,vx,vy;
    int weight,minweight;
    Edge edge;
    for(i=0;in-1;i++)//V0到其他节点的长度从矩阵中初始化
    {
        mst[i].start_vex = 0;//起点一直是V0
        mst[i].stop_vex = i+1;
        mst[i].weight = graph->arcs[0][i+1];
    }
    for(i=0;in-1;i++)//mis[0]是V0到V1的距离,终点从V1开始
    {
        minweight = Max;//保存权值最小边的权值
        min = i;//保存最小节点
        for(j=i;jn-1;j++)//一轮循环找到此时还未加入的边中权值最小的
        {
            if(mst[j].weight//保存权值最小边的权值
                min = j;//保存最小节点
            }
        }
        edge = mst[min];//结构体可以整体赋值   此时的edge只是一个临时变量
        mst[min] = mst[i];
        mst[i] = edge;//交换  将最小边和第一个mst[i]交换,保证最外层i循环下次循环时不会再从已经加入的边中加权值最小的边,此时mst[i]为已经加入的最小边
        vx = mst[i].stop_vex;//记录终点
        printf("%6d %6d\n",mst[i].start_vex,mst[i].stop_vex);//此时这条边已经加入,所以打印出来
        for(j=i+1;jn-1;j++)//用新加入的边的终点当做起点,对mst原有的其他边进行调整
        {                                       //为什么是i+1因为讲过交换后<=1的mis[]中保存的边已经是确定加入的边,不再做调整,之所以明确为i+1也是因为经过之前边的交换
            vy = mst[j].stop_vex;//如果将原有边的起点换成新加入边的终点
            weight = graph->arcs[vx][vy];//权值是否会减小
            if(weight//如果减小
            {
                mst[j].start_vex = vx;//将原有边的起点改成新加入边的终点
                mst[j].weight = weight;//更新权值
            }
        }//最后一轮调整完毕
    }
}
/*prime算法从mst[]中找到一个最小边,将终点当做起点与其他未加入的边的起点进行权值比较
进行边的调整,     然后这种步骤进行循环,直到加入足够数量的边,也就是n-1条边
*/

mst数组的每一个元素都是边,记录着开始点,结束点和权值。第一个for循环给mst数组的每一个元素赋值,v0到其他各点的权值。第二个for循环比较n-1次,即选出n-1条边。每次都选出mst数组里权值最小的一条边,记录下终止节点。然后把这条边和mst数组里的第i条边互换,因为已选出的边不用再和其他边比较了,下次循环比较是从第i+1元素开始,就不会影响到已经 选出的边了。当前选出的最小边和第i条边交换后,再把选出边的种植节点当成开始节点和i条边之后的边比较,看权值是否会减小,如果新的开始节点使边的权值减小,则用选出边的终止节点代替开始节点.就这样循环i-1次。
最后,mst数组里的元素就都是最小生成树的边了,你可以把mst的元素一个一个打印出来,不过我的程序里是每选好一条边就打印出来。
现在看一下运行截图和主函数吧。

void main()
{
    GraphMatrix *mygraph;
    Edge *mymst;//mymst[]数组形式调用成员用.  (mymst+1)形式调用成员用->
    mygraph = (GraphMatrix*)malloc(sizeof(GraphMatrix));
    mymst = (Edge*)malloc(sizeof(Edge));
    CreateGraph(mygraph,6);
    printf("testing creategraph\n");
    printf("testing prim:\n");
    printf("start_vex stop_vex\n");
    prim(mygraph,mymst);
}

最小生成树PRIM算法_第2张图片

你可能感兴趣的:(prim,结构,数据结构,算法,数据结构)