‘壹’ KRUSKAL算法,提点改进的意见
很谦虚的学习精神哈,我觉得已经很好了(可能是我初学的缘故?),如果你说的更好使要求时间的话,可以把冒泡排序改成别的排序,比如O(nlgn)的
‘贰’ kruskal算法 如何判环
kruskal需要用并查集。
每次从边集中找权值最小的,如果两顶点不在同一集合,就加上边权,并合并两个点。
‘叁’ kruskal算法是什么
克鲁斯卡尔算法。
克鲁斯卡尔算法是求连通网的最小生成树的另一种方法。与普里姆算法不同,它的时间复杂度为O(eloge)(e为网中的边数),所以,适合于求边稀疏的网的最小生成树。
克鲁斯卡尔算法基本思想:
克鲁斯卡尔(Kruskal)算法从另一途径求网的最小生成树。其基本思想是:假设连通网G=(V,E),令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),概述图中每个顶点自成一个连通分量。
在E中选择代价最小的边,若该边依附的顶点分别在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边而选择下一条代价最小的边。依此类推,直至T中所有顶点构成一个连通分量为止。
‘肆’ kruskal算法
给每个子树一个不同的编号,对每一个顶点引入一个标记t,表示这个顶点所在的子树编号。当加入一条红色边,就会使该边两端点所在的两个子树连接起来,成为一个子树,从而两个子树中的顶点标记要改变成一样。综上,可将Kruskal算法细化使其更容易计算机实现。
kruskal应该是递归算法吧,在定义图中各端点时,可以多设一个标记,把图递归遍历一遍,在同一连同子图上的点,标记为一样的整型数值即可。
参考:http://ke..com/view/580403.htm
‘伍’ 求kruskal算法的C语言程序 越简单越好a
对于c语言,指针是灵魂,特别是在稍微高级点的程序中,指针是必不可少的。以下程序没有用到链表,结构体用到了。当然如果你一定要用二维数组代替结构体去存储也行,代码会变得相当麻烦而且可读性差,维护困难。
另外注释加上了。代码临时写成,自带个人风格呵呵。
#include <stdio.h>
#include <stdlib.h>
#define TURE 1
#define FALSE 0
#define MAX 1000
#define abs(a) a > 0 ? a : -a
//图相关----------------------
typedef struct Tnode
{
int loc;
struct Tnode *next;
} Tnode; //顶点存放结点
typedef struct Ttable
{
Tnode *head;
Tnode *rear;
int length;
} Ttable; //顶点链表结构
typedef int ArcCell; /*对于无权图,用1或0表示是否相邻;对带权图,则为权值类型*/
typedef int booleanType; //状态变量
typedef struct
{
ArcCell **arcs; /*邻接矩阵*/
int vexnum; /*图的顶点数和弧数*/
} MGraph; /*(Adjacency Matrix Graph)*/
//----------------------------
//队列相关(链式)-------------
typedef struct QNode //队列结点
{
int data;
struct QNode *next;
} QNode;
typedef struct //队列
{
QNode *front, *rear;
} LinkQueue;
//-----------------------------
MGraph G; //图
ArcCell **steparcs; //辅助矩阵
Ttable TE; //顶点链表指针
booleanType *visited; //建立标志数组(全局量)
LinkQueue Q; //定义队列
int GetGraph(MGraph *G); //建立图结构
void Back(); //还原矩阵
int kruskalTravel(MGraph G); //克鲁斯卡尔算法建立最小生成树
int MinSearch(MGraph G, int *i, int *j); //查找权值最小的边,以i,j返回其两端顶点。
int FirstAdjVex(int v);
int NextAdjVex(int v, int w);
int InitQueue(LinkQueue *Q); //初始化队列
int EmptyQueue(LinkQueue Q); //判空
int EnQueue(LinkQueue *Q, int v); //入队
int OutQueue(LinkQueue *Q); //出队
int WFSTravel(MGraph *G, LinkQueue *Q, int x, int y); //广度遍历含有i的连通分量,如果含有j顶点,返回TRUE,否则返回FALSE
int main()
{
GetGraph(&G);
printf("Kruskal:\n");
kruskalTravel(G);
return 0;
}
int GetGraph(MGraph *G) //建立邻接矩阵
{
int i, j;
scanf("%d", &(G->vexnum));
G->arcs = (ArcCell**)malloc(sizeof(ArcCell*) * G->vexnum);
for(i = 0; i < G->vexnum; i++)
{
G->arcs[i] = (ArcCell*)malloc(sizeof(ArcCell) * G->vexnum);
} //建立二维动态数组
for(i = 0; i < G->vexnum; i++)
{
for(j = 0; j < G->vexnum; j++)
{
scanf("%d", G->arcs[i] + j);
}
} //输入数据
return 0;
}//GetGraph
int kruskalTravel(MGraph G) //克鲁斯卡尔算法建立最小生成树
{
int i, j;
int N = G.vexnum;
steparcs = (ArcCell**)malloc(sizeof(ArcCell*) * G.vexnum); //建立二维动态数组
for(i = 0; i < G.vexnum; i++)
{
steparcs[i] = (ArcCell*)malloc(sizeof(ArcCell) * G.vexnum);
} //建立二维动态数组
for(i = 0; i < G.vexnum; i++) //初始化辅助矩阵
{
for(j = 0; j < G.vexnum; j++)
{
steparcs[i][j] = 0;
printf("%d ", steparcs[i][j]);
}
printf("\n");
}
printf("\n");
while(N > 1) //只要剩余的连通分量大于一,就继续链接各个连通分量
{
//查找权值最小的边,以i,j返回其两端顶点。如果两个顶点属于同一连通分量,则查找权次最小边,标志矩阵为负
MinSearch(G, &i, &j);
if(!WFSTravel(&G, &Q, i, j)) //广度遍历含有i的连通分量,如果含有j顶点,返回TRUE,否则返回FALSE
{
steparcs[i][j] = steparcs[j][i] = G.arcs[i][j]; //将符合条件的边和顶点并入到连通分量中
G.arcs[i][j] *= -1; //标志邻接矩阵,表明此条边已经查询过
G.arcs[j][i] *= -1;
N--; //剩余的连通分量
for(i = 0; i < G.vexnum; i++) //输出本次步骤
{
for(j = 0; j < G.vexnum; j++)
{
printf("%d ", steparcs[i][j]);
}
printf("\n");
}
printf("\n");
} //if
} //while
return 0;
}
int MinSearch(MGraph G, int *i, int *j) //查找权值最小的边,返回其值,并以i,j返回其两端顶点。
{
int temp = MAX; //存放当前最小值
int m, n;
for(n = 0; n < G.vexnum; n++) //循环查找
{
for(m = 0; m < G.vexnum; m++)
{
if(G.arcs[n][m] > 0 && G.arcs[n][m] < temp) //找最小值
{
temp = G.arcs[n][m];
*i = n;
*j = m;
}
}
}
return temp;
}
int FirstAdjVex(int v)
{
int i;
for(i = 0; i < G.vexnum; i++)
if(steparcs[v][i] != 0)
return i;
return -1;
}
// 返回下一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1
int NextAdjVex(int v, int w)
{
int i;
for(i = w + 1; i < G.vexnum; i++)
if(steparcs[v][i] != 0)
return i;
return -1;
}
int InitQueue(LinkQueue *Q) //初始化队列
{
Q->front = Q->rear = (QNode*)malloc(sizeof(QNode)); //头结点
return 0;
}
int EmptyQueue(LinkQueue Q) //判空
{
return Q.front == Q.rear ? 1 : 0;
}
int EnQueue(LinkQueue *Q, int v) //入队
{
Q->rear->next = (QNode*)malloc(sizeof(QNode));
Q->rear = Q->rear->next;
Q->rear->data = v;
return 0;
}
int OutQueue(LinkQueue *Q) //出队
{
int e;
QNode *p;
if(Q->front == Q->rear)
{
printf("Queue Empty\n");
exit(0);
}
p = Q->front;
Q->front = Q->front->next;
e = Q->front->data;
free(p);
return e; //返回队头元素
}
//广度遍历含有i的连通分量,如果含有j顶点,返回TRUE,否则返回FALSE
int WFSTravel(MGraph *G, LinkQueue *Q, int x, int y)
{
int v, vtop = x, i;
visited = (booleanType*)malloc(sizeof(booleanType) * G->vexnum);
InitQueue(Q);
for(v = 0; v < G->vexnum; v++) //初始化标志数组
{
visited[v] = FALSE;
}
v = vtop; //初始查询顶点
if(!visited[v]) //如果没有遍历过,从此处开始遍历
{
visited[v] = TURE; //遍历该结点并标志结点状态
EnQueue(Q, v);
while(!EmptyQueue(*Q)) //如果队列中有元素,继续访问其邻接点
{
i = OutQueue(Q);
for(v = FirstAdjVex(i); v >= 0; v = NextAdjVex(i, v)) //寻找一个顶点的所有邻接点
{
if(!visited[v]) //访问未访问过的顶点
{
visited[v] = TURE;
if(v == y)
{
G->arcs[x][y] *= -1; //标志邻接矩阵,表明此条边已经查询过
G->arcs[y][x] *= -1;
return 1;
}
EnQueue(Q, v);
}
} //寻找一个顶点的所有邻接点
} //如果队列中有元素,继续访问其邻接点
} //如果没有遍历过,从此处开始遍历
return 0;
}//WFSprint
‘陆’ kruskal算法的代码实现
MST-KRUSKAL(G,w)
function Kruskal(w,MAX)
%此程序为最小支撑树的Kruskal算法实现
%w为无向图的距离矩阵,故为对称矩阵
%MAX为距离矩阵中∞的实际输入值
%时间:2011年6月22日0:07:53
len=length(w); %图的点数
edge=zeros(len*(len-1),3); %用于存储图中的边
count=1; %图中的边数
for i=1:len-1 %循环距离矩阵,记录存储边
for j=i+1:len
if w(i,j)~=MAX
edge(count,1)=w(i,j);
edge(count,2)=i;
edge(count,3)=j;
count=count+1;
end
end
end
edge=edge(1:count-1,:); %去掉无用边
[tmp,index]=sort(edge(:,1)); %所有边按升序排序
i=3; %其实测试边数为3条(3条以下无法构成圈,即无需检测)
while 1
x=findcycle(edge(index(1:i),:),len); %检测这些边是否构成圈
if x
index(i)=0; %若构成圈,则将该边对应的index项标记为0,以便除去
else
i=i+1; %若没有构成圈,则i加1,加入下一边检测
end
index=index(index>0); %将构成圈的边从index中除去
if i==len
break; %找到符合条件的点数减一条的边,即找到一个最小支撑树
end
end
index=index(1:len-1); %截短index矩阵,保留前len-1项
%%%%%%%%%%%% 结果显示 %%%%%%%%%%%%%
s=sprintf('
%s %s %s ','边端点','距离','是否在最小支撑树');
for i=1:count-1
edge_tmp=edge(i,:);
if ~isempty(find(index==i,1))
s_tmp=sprintf('
(%d,%d) %d %s ',edge_tmp(2),edge_tmp(3),edge_tmp(1),'√');
else
s_tmp=sprintf('
(%d,%d) %d %s ',edge_tmp(2),edge_tmp(3),edge_tmp(1),'×');
end
s=strcat(s,s_tmp);
end
disp(s);
end
function isfind=findcycle(w,N)
%本程序用于判断所给的边能否构成圈:有圈,返回1;否则返回0
%w:输入的边的矩阵
%N:原图的点数
%原理:不断除去出现次数小于2的端点所在的边,最后观察是否有边留下
len=length(w(:,1));
index=1:len;
while 1
num=length(index); %边数
p=zeros(1,N); %用于存储各点的出现的次数(一条边对应两个端点)
for i=1:num %统计各点的出现次数
p(w(index(i),2))=p(w(index(i),2))+1;
p(w(index(i),3))=p(w(index(i),3))+1;
end
index_tmp=zeros(1,num); %记录除去出现次数小于2的端点所在的边的边的下标集合
discard=find(p<2); %找到出现次数小于2的端点
count=0; %记录剩余的边数
for i=1:num
%判断各边是否有仅出现一次端点——没有,则记录其序号于index_tmp
if ~(~isempty(find(discard==w(index(i),2),1)) || ~isempty(find(discard==w(index(i),3),1)))
count=count+1;
index_tmp(count)=index(i);
end
end
if num==count %当没有边被被除去时,循环停止
index=index_tmp(1:count); %更新index
break;
else
index=index_tmp(1:count); %更新index
end
end
if isempty(index) %若最后剩下的边数为0,则无圈
isfind=0;
else
isfind=1;
end
end
%
% a =[
% 0 3 2 3 100 100 100
% 3 0 2 100 100 100 6
% 2 2 0 3 100 1 100
% 3 100 3 0 5 100 100
% 100 100 100 5 0 4 6
% 100 100 1 100 4 0 5
% 100 6 100 6 100 5 0];
%
% Kruskal(a,100) {
最小生成树的Kruskal算法。
Kruskal算法基本思想:
每次选不属于同一连通分量(保证不生成圈)且边权值最小的顶点,将边加入MST,并将所在的2个连通分量合并,直到只剩一个连通分量
排序使用Quicksort(O(eloge))
检查是否在同一连通分量用Union-Find,每次Find和union运算近似常数
Union-Find使用rank启发式合并和路径压缩
总复杂度O(eloge)=O(elogv) (因为e<n(n-1)/2)
} constmaxn=100;maxe=maxn*maxn;typeedge=recorda,b:integer;//边的2个顶点len:integer;//边的长度end;varedges:array[0..maxe]ofedge;//保存所有边的信息p,r:array[0..maxn]ofinteger;//p保存i的父亲节点,r用来实现Union-Find的rank启发式n,e:integer;//n为顶点数,e为边数procereswap(a,b:integer);//交换beginedges[0]:=edges[a];edges[a]:=edges[b];edges[b]:=edges[0];end;procerequicksort(l,r:integer);//快速排序varx,i,j:integer;beginx:=edges[random(r-l+1)+l].len;i:=l;j:=r;repeatwhileedges[i].len<xdoinc(i);whileedges[j].len>xdodec(j);ifi<=jthenbeginswap(i,j);inc(i);dec(j);enntili>j;ifl<jthenquicksort(l,j);ifi<rthenquicksort(i,r);end;procereinit;vari:integer;beginassign(input,'g.ini');reset(input);readln(n,e);fori:=1toedoreadln(edges[i].a,edges[i].b,edges[i].len);//从文件读入图的信息fori:=1tondop[i]:=i;//初始化并查集randomize;quicksort(1,e);//使用快速排序将边按权值从小到大排列end;functionfind(x:integer):integer;//并查集的Find,用来判断2个顶点是否属于一个连通分量beginifx<>p[x]thenp[x]:=find(p[x]);find:=p[x]end;procereunion(a,b:integer);//如果不属于且权值最小则将2个顶点合并到一个连通分量vart:integer;begina:=find(a);b:=find(b);ifr[a]>r[b]thenbegint:=a;a:=b;b:=tend;ifr[a]=r[b]theninc(r[a]);p[a]:=b;end;procerekruskal;//主过程varen:integer;//en为当前边的编号count:integer;//统计进行了几次合并。n-1次合并后就得到最小生成树tot:integer;//统计最小生成树的边权总和begincount:=0;en:=0;tot:=0;whilecount<n-1dobegininc(en);withedges[en]dobeginiffind(a)<>find(b)thenbeginunion(a,b);writeln(a,'--',b,':',len);inc(tot,len);inc(count);end;end;end;writeln('TotalLength=',tot)end;{===========main==========}begininit;kruskal;end.Kruskal算法适用于边稀疏的情形,而Prim算法适用于边稠密的情形 importjava.util.ArrayList;importjava.util.Collections;classBianimplementsComparable//两点之间的加权边{privateintfirst,second;//表示一条边的两个节点privateintvalue;//权值publicBian(intfirst,intsecond,intvalue){this.first=first;this.second=second;this.value=value;}publicintgetFirst(){returnfirst;}publicintgetSecond(){returnsecond;}publicintgetValue(){returnvalue;}@OverridepublicintcompareTo(Objectarg0){returnvalue>((Bian)arg0).value1:(value==((Bian)arg0).value0:-1);}@OverridepublicStringtoString(){returnBian[first=+first+,second=+second+,value=+value+];}}classShuZu{staticArrayList<ArrayList>list=newArrayList<ArrayList>();//存放每一个数组中的节点的数组staticArrayList<ArrayList>bianList=newArrayList<ArrayList>();//对应存放数组中的边的数组publicstaticvoidcheck(Bianb)//检查在哪个数组中{if(list.size()==0){ArrayList<Integer>sub=newArrayList<Integer>();sub.add(b.getFirst());sub.add(b.getSecond());list.add(sub);ArrayList<Bian>bian=newArrayList<Bian>();bian.add(b);bianList.add(bian);return;}intfirst=b.getFirst();intshuyu1=-1;intsecond=b.getSecond();intshuyu2=-1;for(inti=0;i<list.size();i++)//检查两个节点分别属于哪个数组{for(intm=0;m<list.get(i).size();m++){if(first==(Integer)list.get(i).get(m))shuyu1=i;if(second==(Integer)list.get(i).get(m))shuyu2=i;}}if(shuyu1==-1&&shuyu2==-1)//表示这两个节点都没有需要新加入{ArrayList<Integer>sub=newArrayList<Integer>();sub.add(b.getFirst());sub.add(b.getSecond());list.add(sub);ArrayList<Bian>bian=newArrayList<Bian>();bian.add(b);bianList.add(bian);}if(shuyu1==-1&&shuyu2!=-1)//表示有一个点已经在数组中只把另一个加入就可以了{list.get(shuyu2).add(first);bianList.get(shuyu2).add(b);}if(shuyu2==-1&&shuyu1!=-1)//表示有一个点已经在数组中只把另一个加入就可以了{list.get(shuyu1).add(second);bianList.get(shuyu1).add(b);}if(shuyu1==shuyu2&&shuyu1!=-1)//表述两个在同一个组中会形成环{}if(shuyu1!=shuyu2&&shuyu1!=-1&&shuyu2!=-1)//表示两个点在不同的组中需要合并{for(inti=0;i<list.get(shuyu2).size();i++){list.get(shuyu1).add(list.get(shuyu2).get(i));}list.remove(shuyu2);for(inti=0;i<bianList.get(shuyu2).size();i++){bianList.get(shuyu1).add(bianList.get(shuyu2).get(i));}bianList.get(shuyu1).add(b);bianList.remove(shuyu2);}}publicstaticvoidshow(){for(inti=0;i<bianList.get(0).size();i++)System.out.println(bianList.get(0).get(i));}}publicclassTest{publicstaticvoidmain(String[]args){ArrayList<Bian>l=newArrayList<Bian>();l.add(newBian(1,3,1));l.add(newBian(1,2,6));l.add(newBian(1,4,5));l.add(newBian(2,3,5));l.add(newBian(2,5,3));l.add(newBian(3,4,5));l.add(newBian(3,5,6));l.add(newBian(3,6,4));l.add(newBian(4,6,2));l.add(newBian(5,6,6));Collections.sort(l);//for(inti=0;i<l.size();i++)//System.out.println(l.get(i));for(inti=0;i<l.size();i++)ShuZu.check(l.get(i));ShuZu.show();}}
‘柒’ kruskal算法java实现,哪位大神能帮忙调通这段代码!
算法如何,就不懂了。但,代码已经正常编译、运行 了
importjava.util.*;
importjava.io.*;
publicclassKruskalTest{
privatestaticfinalintm=3501981;//边数
privatestaticfinalintn=2647;//顶点数
privatestaticint[]parent=newint[n];//parent数组,长度为顶点数
privatestaticArrayList<Edge>list;//序列
privatestaticfloatsum=0;//最小生成树边权总和
publicstaticvoidmain(String[]args)throwsFileNotFoundException{
newKruskalTest().test();
}
publicvoidtest()throwsFileNotFoundException{
Filefile=newFile(".\Euclideandistance.xlsx");
//读取文件
Scannersc=newScanner(file);
doublenumber;
list=newArrayList<Edge>();
for(inti=1;i<=n;i++)
for(intj=i;j<=n;j++){
Edgeedge=newEdge();
edge.u=i;
edge.v=j;
if(sc.hasNext()){
number=sc.nextDouble();
edge.w=number;
}list.add(edge);
}
Collections.sort(list,newComparator<Edge>(){
@Override
publicintcompare(Edgeo1,Edgeo2){
return(int)(o1.w-o2.w);
}
});
//for(inti=0;i<list.size();i++){
//Edgeedge=list.get(i);
//System.out.println(edge.u+""+edge.v+""+edge.w);
//}
kruskal();
System.out.println("thelengthofMSTis"+sum);
}
staticvoipset(){
for(inti=0;i<n;i++)
parent[i]=-1;
}
intfind(intx){
ints;
for(s=x;parent[s]>=0;s=parent[s]);
while(s!=x){
inttmp=parent[x];
parent[x]=s;
x=tmp;
}returns;
}
voinion(intR1,intR2){
intr1=find(R1);
intr2=find(R2);
inttemp=parent[r1]+parent[r2];
if(parent[r1]>parent[r2]){
parent[r1]=r2;
parent[r2]=temp;
}else{
parent[r2]=r1;
parent[r1]=temp;
}
}
voidkruskal(){
intnum=0;
intu,v;
upset();
for(inti=0;i<m;i++){
Edgeedge=(Edge)list.get(i);
u=edge.u;
v=edge.v;
if(find(u)!=find(v)){
sum+=edge.w;
union(u,v);
num++;
}
if(num>=n-1)break;
}
}
classEdge{
intu,v;
doublew;
}
}
‘捌’ 用kruskal算法实现最小生成树写出选边的过程并编程实现,要写程序
#include <stdio.h>
#include <stdlib.h>
#define N 10010
#define M 10010
typedef struct edge
{
int a,b,c;
}edge;
edge e[M];
int n,m;//n个结点,m条边
int p[N];
void make_set()
{
for(int i=1;i<=n;i++) p[i]=i;
}
int find_set(int i)
{
if(i!=p[i]) p[i]=find_set(p[i]);
return p[i];
}
void union_set(int i,int j)
{
i=find_set(i);
j=find_set(j);
p[j]=i;
}
int cmp(const void*a,const void*b)
{
return (((edge*)a)->c)-(((edge*)b)->c);
}
int main()
{
//此处为文件读写操作
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int i,min;
while(~scanf("%d%d",&n,&m))
{
for(i=0;i<m;i++)
{
scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
}
qsort(e,m,sizeof(e[0]),cmp);
make_set();
min=0;
for(i=0;i<m;i++)
{
if(find_set(e[i].a)==find_set(e[i].b)) continue;
union_set(e[i].a,e[i].b);
min+=e[i].c;
}
printf("%d\n",min);
}
return 0;
}
‘玖’ kruskal算法的举例描述
克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个。这里面充分体现了贪心算法的精髓。大致的流程可以用一个图来表示。这里的图的选择借用了Wikipedia上的那个。非常清晰且直观。
首先第一步,我们有一张图,有若干点和边
第一步我们要做的事情就是将所有的边的长度排序,用排序的结果作为我们选择边的依据。这里再次体现了贪心算法的思想。资源排序,对局部最优的资源进行选择。
排序完成后,我们率先选择了边AD。这样我们的图就变成了
.
.
.
.
.
.
第二步,在剩下的边中寻找。我们找到了CE。这里边的权重也是5
.
.
.
.
.
.
依次类推我们找到了6,7,7。完成之后,图变成了这个样子。
.
.
.
.
.
.
下一步就是关键了。下面选择那条边呢? BC或者EF吗?都不是,尽管现在长度为8的边是最小的未选择的边。但是他们已经连通了(对于BC可以通过CE,EB来连接,类似的EF可以通过EB,BA,AD,DF来接连)。所以我们不需要选择他们。类似的BD也已经连通了(这里上图的连通线用红色表示了)。
最后就剩下EG和FG了。当然我们选择了EG。最后成功的图就是下图:
.
.
.
.
.
.
到这里所有的边点都已经连通了,一个最小生成树构建完成。
Kruskal算法的时间复杂度由排序算法决定,若采用快排则时间复杂度为O(N log N)。
‘拾’ kruskal算法的java实现作为毕业设计是不是太简单了 最后怕过不了
您好,提问者:
这要看你的思维跟练习程度了。多动脑,找找规律!