图--最小生成树

最小生成树实际上指的是“最小权值生成树“

生成树是连通图的极小连通子图。所谓极小是指:若在树中任意增加一条边,则将出现一个回路;若去掉一条边,将会使之变成非连通图。 生成树各边的权值总和称为生成树的权。权最小的生成树称为最小生成树。

最小生成树的性质

用哲学的观点来说,每个事物都有自己特有的性质,那么图的最小生成树也是不例外的。按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点、n-1 条边。

最小生成树的寻找方法主要有两个方法:

Kruscal算法:http://www.cnblogs.com/ktyanny/archive/2009/12/10/1621034.html

prim算法:http://www.cnblogs.com/ktyanny/archive/2009/12/15/1625020.html

###################

kruscal算法思想:

用ktyanny的口头陈述为,Kruscal算法实质是非朴素的贪心策略。初始状态,图的每个节点单独作为一个集合,图的边就绪状态为非降序排列。然后一次遍历图中的所有边(u, v),使用并查集的思想(不懂并查集的点击此处 并查集(不相交集合)
进行学习find_set(u)如果不等于find_set(v),也就是u和v不在同一个集合中,那么相当于判断了添加了边(u, v)不会照成环。(用算法导论的话来说,就是find_set(u)返回的是集合u中的一个代表元素。在下面的《大话数据结构》代码中,采用的是寻找父节点的方法:所有的集合,每一个集合的父节点最终都会到一个节点上去。)好!接下来的工作就是把需要的信息保存起来(比如边的信息之类的),同时合并u和v(使用union_set(u, v)).当所有的顶点都添加到集合中去了,好!算法完毕。

下面是kruscal算法代码:

#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;    /* Status是函数的类型,其值是函数结果状态代码,如OK等 */

#define MAXEDGE 20
#define MAXVEX 20
#define INFINITY 65535

typedef struct
{
    int arc[MAXVEX][MAXVEX];
    int numVertexes, numEdges;
}MGraph;

typedef struct
{
    int begin;
    int end;
    int weight;
}Edge;   /* 对边集数组Edge结构的定义 */

/* 构件图 */
void CreateMGraph(MGraph *G)
{
    int i, j;

    /* printf("请输入边数和顶点数:"); */
    G->numEdges=15;
    G->numVertexes=9;

    for (i = 0; i < G->numVertexes; i++)/* 初始化图 */
    {
        for ( j = 0; j < G->numVertexes; j++)
        {
            if (i==j)
                G->arc[i][j]=0;
            else
                G->arc[i][j] = G->arc[j][i] = INFINITY;
        }
    }

    G->arc[0][1]=10;
    G->arc[0][5]=11; 
    G->arc[1][2]=18; 
    G->arc[1][8]=12; 
    G->arc[1][6]=16; 
    G->arc[2][8]=8; 
    G->arc[2][3]=22; 
    G->arc[3][8]=21; 
    G->arc[3][6]=24; 
    G->arc[3][7]=16;
    G->arc[3][4]=20;
    G->arc[4][7]=7; 
    G->arc[4][5]=26; 
    G->arc[5][6]=17; 
    G->arc[6][7]=19; 

    for(i = 0; i < G->numVertexes; i++)
    {
        for(j = i; j < G->numVertexes; j++)
        {
            G->arc[j][i] =G->arc[i][j];
        }
    }

}

/* 交换权值 以及头和尾 */
void Swapn(Edge *edges,int i, int j)
{
    int temp;
    temp = edges[i].begin;
    edges[i].begin = edges[j].begin;
    edges[j].begin = temp;
    temp = edges[i].end;
    edges[i].end = edges[j].end;
    edges[j].end = temp;
    temp = edges[i].weight;
    edges[i].weight = edges[j].weight;
    edges[j].weight = temp;
}

/* 对权值进行排序 */
void sort(Edge edges[],MGraph *G)
{
    int i, j;
    for ( i = 0; i < G->numEdges; i++)
    {
        for ( j = i + 1; j < G->numEdges; j++)
        {
            if (edges[i].weight > edges[j].weight)
            {
                Swapn(edges, i, j);
            }
        }
    }
    printf("权排序之后的为:\n");
    for (i = 0; i < G->numEdges; i++)
    {
        printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
    }

}

/* 查找连线顶点的尾部下标 */
int Find(int *parent, int f)
{
    while ( parent[f] > 0)
    {
        f = parent[f];
    }
    return f;
}

/* 生成最小生成树 */
void MiniSpanTree_Kruskal(MGraph G)
{
    int i, j, n, m;
    int k = 0;
    int parent[MAXVEX];/* 定义一数组用来判断边与边是否形成环路 */
    
    Edge edges[MAXEDGE];/* 定义边集数组,edge的结构为begin,end,weight,均为整型 */

    /* 用来构建边集数组并排序********************* */
    for ( i = 0; i < G.numVertexes-1; i++)
    {
        for (j = i + 1; j < G.numVertexes; j++)
        {
            if (G.arc[i][j]<INFINITY)
            {
                edges[k].begin = i;
                edges[k].end = j;
                edges[k].weight = G.arc[i][j];
                k++;
            }
        }
    }
    sort(edges, &G);
    /* ******************************************* */


    for (i = 0; i < G.numVertexes; i++)
        parent[i] = 0;    /* 初始化数组值为0 */

    printf("打印最小生成树:\n");
    for (i = 0; i < G.numEdges; i++)    /* 循环每一条边 */
    {
        n = Find(parent,edges[i].begin);
        m = Find(parent,edges[i].end);
        if (n != m) /* 假如n与m不等,说明此边没有与现有的生成树形成环路 */
        {
            parent[n] = m;    /* 将此边的结尾顶点放入下标为起点的parent中。 */
                            /* 表示此顶点已经在生成树集合中 */
            printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight);
        }
    }
}

int main(void)
{
    MGraph G;
    CreateMGraph(&G);
    MiniSpanTree_Kruskal(G);
    return 0;
}

 

 

 

posted @ 2013-03-30 17:17  kamendula  阅读(311)  评论(0)    收藏  举报