树的概念:
在一个无向连通图G(V,E)中存在T=(V(T),E(T)),其中V=V(T),E(T)⊆E,则称T是图G的树。(图的树不唯一)
树的主要性质:①在一棵树中任意两点由唯一的路相连②在树中,E=V-1③树中不存在环,任何对树添加边的操作会生成环
最小生成树的概念:
在图G(V,E)中,对G中的每一条边都赋有一个数,称作“权”。权是有关边长的数量指标。在实际应用问题中可代表花费,距离,时间等。在一个无向连通图中,设若每条边的权非负,它的生成树T中所有边的权之和称为该树的权。图的生成树中权最小的那个树称作最小生成树。
求最小生成树的常用方法有两种:Prim算法和Kruskal算法。
Prim算法
Prim算法需设置两个集合P,Q,其中P用于存放最小生成树的顶点,Q用于存放最小生成树的边。
1.构造最小生成树时需确定起点v1并将其存放在集合P中(此时Q集合为空集),同时从在集合V-P中寻找与v1通过唯一路且权值最小相连的顶点,将其放入集合P,将此路放入集合Q中。
2.以新找到的顶点为起点重复以上过程,直到V中所有顶点都在P,即树生成。
注:
最初的起点是任意确定的;
寻找最小权值的路时不应包含Q中已保存的路。
算法实例:
该图的接邻矩阵为:
Matlab程序:
clc;clear;
a=zeros(7);
a(1,2)=5;a(1,3)=9;a(1,4)=8;a(1,6)=11;a(1,7)=6;
a(2,3)=6;
a(3,4)=3;a(3,5)=10;a(3,6)=12;
a(4,5)=4;a(4,7)=9;
a(5,6)=5;
a(6,7)=4;
a=a+a';
a(a==0)=inf;
result=[];p=1;tb=2:length(a);
while size(result,2)~=length(a)-1
temp=a(p,tb);temp=temp(:);
d=min(temp);
[jb,kb]=find(a(p,tb)==d);
j=p(jb(1));k=tb(kb(1));
result=[result,[j;k;d]];p=[p,k];tb(find(tb==k))=[];
end
result
运行结果:
result的第一、二、三行分别表示最小生成树边的起点、终点、权集合
Kruskal算法
Kruskal算法需要集合Q用来放置图G中所有的路,集合P来放置选中的最小生成树的路。
具体操作方法如下:
将图G中所有的路按权值从小到大排列,然后依次取出权值较小的边路。如果路的两个顶点不在同一棵树上则合并两棵树,将此路从集合Q中移除,加入集合P中。如果路的两个顶点位于同一棵树上,则忽略对此路的操作。重复以上过程,直到遍历所有路,若有唯一的生成树生成,则最小生成树生成。时间复杂度为O(ElogV)
算法实例(同上):
该图的接邻矩阵:
Matlab程序:
clc;clear; a=zeros(7); a(1,2)=5;a(1,3)=9;a(1,4)=8;a(1,6)=11;a(1,7)=6; a(2,3)=6; a(3,4)=3;a(3,5)=10;a(3,6)=12; a(4,5)=4;a(4,7)=9; a(5,6)=5; a(6,7)=4; [i,j,b]=find(a); data=[i';j';b'];index=data(1:2,:); loop=length(a)-1; result=[]; while length(result)<loop temp=min(data(3,:)); flag=find(data(3,:)==temp); flag=flag(1); v1=index(1,flag);v2=index(2,flag); if v1~=v2 result=[result,data(:,flag)]; end index(find(index==v2))=v1; data(:,flag)=[]; index(:,flag)=[]; end result
运行结果:
总结:Prim算法与Kruskal算法都用于寻找并生成最小生成树。但Prim算法从顶点出发寻找与之相连的最短边,最终生成树,而Kruskal算法从边出发,以最短边为目标,不断加入不形成回路的边从而找到最小生成树。
最小生成树的应用: