之前的Prim算法是基于顶点查找的算法,而Kruskal则是从边入手。

通俗的讲:就是希望通过 边的权值大小 来寻找最小生成树。(所有的边称为边集合,最小生成树形成的过程中的顶点集合称为W)

    选取边集合中权值最小的边,查看边的两个顶点是否能和集合W构成环路,若能构成环路,则舍去;否则选取下一条最小权值边重复上一步。

    这里需要注意一个问题,我们从最小权值的边开始寻找最小生成树,

    判断当即将选入的边的两个顶点是否会和已经在集合中的顶点构成环路,这个是我们需要解决的问题。

先说下Kruskal算法的数学语言:

假设连通网N={V,{E}},则令最小生成树的初始状态只有n个顶点而无边的非连通图(T=(V,{})),图中每个顶点自成一个连通分量。

在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。

依次类推,直到T中所有顶点都在同一连通分量上为止。

过程:

问题:

1.边的存储和排序。

2.判断新边是否会形成环路。

问题1比较好解决。可以用一个结构来存放,然后从小到大排序。

问题2比较麻烦:

怎么通过一个方法来判断新加入的边是否对已经归纳好的边形成环路。总是有牛人想出一些非常巧妙的方法,向他们致敬。

以我的图为例,我第一次出现环路的边是在第五幅图:

如果我们建立边的结构时候,将下标数字小的作为起点,数字大的作为终点。比如边(v5,v6)存放格式为

start:5,end:6,weight:3。

同理边(v4,v6)

start:4,end:6,weight:5。

当我们找到边(v4,v5)的时候,怎么可以让这条线被舍弃。刚才我们设置的路线上看,v4——>v6,v5——>v6是否可以通过这样的指向方式来确定两个点是否连通?

这样,如果v4和v5的边被选中,则会出现 v4,v5,v6三个点构成环路。这样我们可以用一个数组来指示Vx点所指示下一个点的下标,递归的遍历该下标,直到找到连接该点的终点。

所以,当一个边是否被选入,此时递归寻找他的两个顶点最终的指向,如果不相等则表示不会构成回路;若相等,则表示构成了回路,需要舍弃。

上图中的箭头线是表示该顶点记录指向的顶点。旁边说明: 比如 e在图中是由(v6,v7),而实际上是边(v4,v7)。

比如边(v2,v3),v3->v7->v2 与 v2 相等了,所以要舍弃这条边。

代码:

int findsrc(int i)
{ while (g_vexto[i])
{
i = g_vexto[i];
}
return i;
} void kruskal(MGraph g,Edges *p)
{
int i,j;
int length=;
int m,n;
for (i=;i<g.numEdges;i++)
{
m = p[i].start;
n = p[i].end;
printf("(%d,%d)",m,n); m=findsrc(m);
n=findsrc(n);
printf("find:(%d,%d)",m,n);
if (m != n)
{
g_vexto[m]=n;
length += p[i].weight;
printf("--->(%d,%d)--->\n",p[i].start,p[i].end);
}
else
{
printf("\n");
}
}
printf("length:%d\n",length);
}

这里调用的前提是 Edges *p 是按照权值的递增排列的。

按照之前讲解的过程,编写不难。

完整代码:

// grp-kruskal.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <stdlib.h> #define MAXVEX 100
#define IFY 65535 typedef char VertexType;
typedef int EdgeType; bool g_visited[MAXVEX];
int g_vexto[MAXVEX]; VertexType g_init_vexs[MAXVEX] = {'A','B','C','D','E','F','G','H','I'}; EdgeType g_init_edges[MAXVEX][MAXVEX] = {
{,,IFY,IFY,IFY,,IFY,IFY,}, //'A'
{,,,IFY,IFY,IFY,IFY,IFY,}, //'B'
{IFY,,,,IFY,IFY,IFY,IFY,IFY},//'C'
{IFY,IFY,,,,IFY,IFY,IFY,IFY},//'D'
{IFY,IFY,IFY,,,,,,IFY}, //'E'
{,IFY,IFY,IFY,,,,IFY,IFY}, //'F'
{IFY,IFY,IFY,IFY,,,,IFY,IFY}, //'G'
{IFY,IFY,IFY,IFY,,IFY,IFY,,IFY}, //'H'
{,,IFY,IFY,IFY,IFY,IFY,IFY,}, //'I'
}; //==========================================================================
//静态图-邻接矩阵
typedef struct {
VertexType vexs[MAXVEX];
EdgeType Mat[MAXVEX][MAXVEX];
int numVexs,numEdges;
}MGraph; typedef struct {
EdgeType weight;
int start;
int end;
}Edges;
//====================================================================
//打印矩阵
void prt_maxtix(EdgeType *p,int vexs)
{
int i,j;
for (i=;i<vexs;i++)
{
printf("\t");
for (j=;j<vexs;j++)
{
if( (*(p + MAXVEX*i + j)) == IFY)
{
printf(" $ ");
}
else
{
printf(" %2d ", *(p + MAXVEX*i + j));
}
}
printf("\n");
}
} //check the number of vextex
int getVexNum(VertexType *vexs)
{
VertexType *pos = vexs;
int cnt=;
while(*pos <= 'Z' && *pos >= 'A')
{
cnt++;
pos++;
}
return cnt;
} bool checkMat(EdgeType *p,VertexType numvex)
{
int i,j;
for (i=;i<numvex;i++)
{
for(j=i+;j<numvex;j++)
{
//printf("[%d][%d] = %d\t",i,j,*(p + MAXVEX*i + j));
//printf("[%d][%d] = %d\n",j,i,*(p + MAXVEX*j + i));
if (*(p + MAXVEX*i + j) != *(p + MAXVEX*j +i) )
{
printf("ERROR:Mat[%d][%d] or Mat[%d][%d] not equal!\n",i,j,j,i);
return false;
}
}
}
return true;
} void init_Grp(MGraph *g,VertexType *v,EdgeType *p)
{
int i,j;
// init vex num
(*g).numVexs = getVexNum(v); //init vexter
for (i=;i<(*g).numVexs;i++)
{
(*g).vexs[i]=*v;
v++;
} //init Mat
for (i=;i<(*g).numVexs;i++)
{
for (j=;j<(*g).numVexs;j++)
{
(*g).Mat[i][j] = *(p + MAXVEX*i + j);
}
}
if(checkMat(&((*g).Mat[][]),(*g).numVexs) == false)
{
printf("init error!\n");
exit();
}
} void CountEdge(MGraph *g)
{
int i,j;
int cnt=;
for (i=;i<(*g).numVexs;i++)
{
for (j=;j<(*g).numVexs;j++)
{ if ((*g).Mat[i][j] == )
{
break;
}
else
{
if ((*g).Mat[i][j] != IFY)
{
//printf("[%d][%d]=%d\n",i,j,(*g).Mat[i][j]);
cnt++;
}
}
}
}
(*g).numEdges=cnt;
printf("num edges is %d\n",cnt);
} void TranMatToEdges(MGraph g,Edges **e)
{
int i,j;
int cnt=;
*e = (Edges*)malloc(g.numEdges*sizeof(Edges)); for (i=;i<g.numVexs;i++)
{
for (j=;j<g.numVexs;j++)
{
if (g.Mat[i][j] == )
{
break;
}
else
{
if (g.Mat[i][j] != IFY)
{
(*e)[cnt].start=j;
(*e)[cnt].end = i;
(*e)[cnt].weight = g.Mat[i][j];
cnt++;
}
}
}
}
}
void sortByWeight(Edges **edge,int len)
{
int i,j;
Edges temp;
for (i=;i<len;i++)
{
for (j=i+;j<len;j++)
{
//printf("cmp:%d,%d\n",(*edge)[i].weight,(*edge)[j].weight);
if ((*edge)[i].weight > (*edge)[j].weight)
{ temp = (*edge)[j]; (*edge)[j]=(*edge)[i]; (*edge)[i]=temp; }
}
}
} int findsrc(int i)
{ while (g_vexto[i])
{
i = g_vexto[i];
}
return i;
} void kruskal(MGraph g,Edges *p)
{
int i,j;
int length=;
int m,n;
for (i=;i<g.numEdges;i++)
{
m = p[i].start;
n = p[i].end;
printf("(%d,%d)",m,n); m=findsrc(m);
n=findsrc(n);
printf("find:(%d,%d)",m,n);
if (m != n)
{
g_vexto[m]=n;
length += p[i].weight;
printf("--->(%d,%d)--->\n",p[i].start,p[i].end);
}
else
{
printf("\n");
}
}
printf("length:%d\n",length);
}
int _tmain(int argc, _TCHAR* argv[])
{
MGraph grp;
//init
init_Grp(&grp,g_init_vexs,&g_init_edges[][]); Edges *pedges=NULL;
//print Matix
prt_maxtix(&grp.Mat[][],grp.numVexs); CountEdge(&grp);
TranMatToEdges(grp,&pedges);
int i; sortByWeight(&pedges,grp.numEdges);
for (i=;i<grp.numEdges;i++)
{
printf("(%d,%d),%d\n",pedges[i].start,pedges[i].end,pedges[i].weight);
}
printf("kruskal\n");
kruskal(grp,pedges); getchar();
return ;
}

结果:

算法学习记录-图——最小生成树之Kruskal算法的更多相关文章

  1. 算法学习记录-图——最小生成树之prim算法

    一个连通图的生成树是一个极小的连通子图,它包含图中全部的顶点(n个顶点),但只有n-1条边. 最小生成树:构造连通网的最小代价(最小权值)生成树. prim算法在严蔚敏树上有解释,但是都是数学语言,很 ...

  2. 算法学习记录-图——最短路径之Dijkstra算法

    在网图中,最短路径的概论: 两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点. 维基百科上面的解释: 这个算法是通过为每个顶点 v 保留目前为止所找到的从 ...

  3. 算法学习记录-图(DFS BFS)

    图: 目录: 1.概念 2.邻接矩阵(结构,深度/广度优先遍历) 3.邻接表(结构,深度/广度优先遍历) 图的基本概念: 数据元素:顶点 1.有穷非空(必须有顶点) 2.顶点之间为边(可空) 无向图: ...

  4. 算法学习记录-图——应用之关键路径(Critical Path)

    之前我们介绍过,在一个工程中我们关心两个问题: (1)工程是否顺利进行 (2)整个工程最短时间. 之前我们优先关心的是顶点(AOV),同样我们也可以优先关心边(同理有AOE).(Activity On ...

  5. 算法学习记录-图——最小路径之Floyd算法

    floyd算法: 解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包. 设为从到的只以集合中的节点为中间节点的最短路径的长度. 若最短路径经过 ...

  6. 算法学习记录-图——应用之拓扑排序(Topological Sort)

    这一篇写有向无环图及其它的应用: 清楚概念: 有向无环图(DAG):一个无环的有向图.通俗的讲就是从一个点沿着有向边出发,无论怎么遍历都不会回到出发点上. 有向无环图是描述一项工程或者系统的进行过程的 ...

  7. 最小生成树的Kruskal算法实现

    最近在复习数据结构,所以想起了之前做的一个最小生成树算法.用Kruskal算法实现的,结合堆排序可以复习回顾数据结构.现在写出来与大家分享. 最小生成树算法思想:书上说的是在一给定的无向图G = (V ...

  8. 数据结构与算法--最小生成树之Kruskal算法

    数据结构与算法--最小生成树之Kruskal算法 上一节介绍了Prim算法,接着来看Kruskal算法. 我们知道Prim算法是从某个顶点开始,从现有树周围的所有邻边中选出权值最小的那条加入到MST中 ...

  9. 23最小生成树之Kruskal算法

    图的最优化问题:最小生成树.最短路径 典型的图应用问题 无向连通加权图的最小生成树 有向/无向加权图的最短路径 四个经典算法 Kruskal算法.Prim算法---------------最小生成树 ...

随机推荐

  1. Sql 2000系统表 语句查询表结构

     SQL2000系统表的应用  –1:获取当前数据库中的所有用户表 select Name from sysobjects where xtype=’u’ and status>=0 –2:获取 ...

  2. 海德汉S3078长度计

    手头有一款海德汉S3078的增量式长度计. 图三为长度计引出线缆的针脚编号,其中,Up和传感器Up短路,0V与传感器0V短路,其他为输出信号线缆.时序如图: Ua1和Ua2两个信号的相位,可以得出长度 ...

  3. jQuery和AJAX基础

    jQuery和AJAX基础 jQuery 基础: 1.jQuery 选择器: 元素选择器:$("p"): #id 选择器:$("#test"): .class ...

  4. AngularJs数据绑定原理

    注 这篇博文主要是写给新手的,是给那些刚刚开始接触Angular,并且想了解数据帮定是如何工作的人.如果你已经对Angular比较了解了,那强烈建议你直接去阅读源代码. Angular用户都想知道数据 ...

  5. Android 仿微信朋友圈添加图片

    github地址(欢迎下载Demo) https://github.com/zhouxu88/WXCircleAddPic 老习惯,先上图,着急用的朋友,直接带走Demo,先拿来用吧,毕竟老板催的紧, ...

  6. github入门之分支操作--5

    1.显示分一览表 2.创建.切换分支 2.1.切换到feature-A分支并进行提交 2.1.1.执行下面的命令,创建名为feature-A的分支 实际上,执行以命令也能收到同样的效果,但是我习惯使用 ...

  7. IOS之TextView属性设置

    UIFontDescriptor *bodyFontDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle:UIFont ...

  8. COGS 788. 昵称

    788. 昵称 ★☆   输入文件:nickname.in   输出文件:nickname.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] ZSUQ送信者与腾讯QQ相似 ...

  9. mac ssd开启trim模式

    开启方法 sudo trimforce enable

  10. URAL 2048 Histroy(打表+模拟)

    因为年历是400年一个循环节的,所以递推出一年的情况,然后递推处理出一个循环节的情况.对于询问,求一个类似前缀和的东西就好了. 跑出来和比样例小一,把A和B加一以后交后AC... 写得时候注意变量的定 ...