图--最小生成树
最小生成树实际上指的是“最小权值生成树“
生成树是连通图的极小连通子图。所谓极小是指:若在树中任意增加一条边,则将出现一个回路;若去掉一条边,将会使之变成非连通图。 生成树各边的权值总和称为生成树的权。权最小的生成树称为最小生成树。
最小生成树的性质
用哲学的观点来说,每个事物都有自己特有的性质,那么图的最小生成树也是不例外的。按照生成树的定义,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; }

浙公网安备 33010602011771号