生成树的概念
一个连通树的生成树是一个极小连通子图,其中含有图中国的全部顶点,和构成一棵树的(n-1)条边。如果在一棵生成树上添加任何一条边,必定构成一个环,因为添加的这条边使得它关联的那两个顶点之间有了第二条路径。
一棵树有n个顶点的生成树(连通无回路图)有且仅有(n-1)条边。如果一个图有n个顶点和小于(n-1)条边,则是非连通图。如果它多于(n-1)条边,则一定有回路。
图中所有生成树中具有边上的权值之和最小的树称为图的最小生成树。
构造最小生成树的准则有以下三条:
- 必须只使用该图中的边来构造最小生成树;
- 必须使用且仅使用(n-1)条边来连接图中的n个顶点;
- 不能使用产生回路的边;
无向图的连通分量和生成树
在对无向图进行遍历时,若是连通图,仅需调用遍历过程(DFS或BFS)一次,从图中的任一顶点出发便可以遍历图中的各个顶点。若是非连通图,则需多次调用遍历过程,每次调用得到的顶点集连同相关的边就构成了图的一个连通分量。
由深度优先遍历得到的生成树称为深度优先生成树(DFS tree)。在深度优先遍历中,如果将每次“前进”(纵向)路过的(将被访问)顶点和边都记录下来,就得到了一个子图,该子图为以出发点为根的树,就是深度优先生成树。相应地,由广度优先遍历得到的生成树称为广度优先生成树(BFS tree)。
这样的生成树由遍历时访问过的n个顶点和遍历时经历的(n-1)条边组成。
对于非连通图,每个连通分量中的顶点集和遍历时走过的边一起构成一棵生成树,各个连通分量的生成树组成非连通图的生成森林(spanning forest)。
普利姆算法
普利姆算法是一种构造性算法,假设G=(V,E)是一个具由n个顶点的带权连通图,T=(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,则由G构造从起始点v出发的最小生成树T的步骤如下:
1.初始化U={v},以v到其他顶点的所有边为候选边。
2.重复以下步骤(n-1)次,使得其他(n-1)个顶点被加入到U中。
(1)从候选边中挑选权值最小的边加入TE,设该边在V-U中的顶点是k,将k加入U中;
(2)考察当前V-U中的所有顶点j,修改候选边,若(k,j)的权值小于原来和顶点j关联的候选边,则用(k,j)取代后者作为候选边。·
Prim算法如下:
void Prim(MatGraph h , int v)
{
int lowcost[MAXV];
int MIN;
int closes[MAXV],i,j,k;
for(i=0;i<g.n;i++)
{
lowcost[i]=g.edges[v][i];
closest[i]=v;
}
for(i=1;i<g.n;i++)
{
MIN = INF;
for(j=0;j,g.n;j++)
if(lowcost[j]!=0 && lowcost[j]<MIN)
{
MIN=lowcost[j];
}
printf(" 边(%d,%d)权为:%d\n",closest[k],k,MIN);
lowcost[k]=0;
for(j=0;j<j.n;j++)
if(lowcost[j]!=0 && g.edse[k][j]<lowcost[j])
{
lowcost[i]=g.edges[k][j];
closest[j]=k;
}
}
}