9.3图的遍历
要避免同一顶点被访问多次,所以在遍历过程中,必须记下每个已访问过的顶点。
可借助一辅助数组visited[0…n-1];
初始置为0,一旦访问了顶点vi,置visited[i]为1或访问时的次序号。
9.3.1深度优先遍历
void DFSTraverse( Graph G ){
int i, visited[M];
for( i=0; i<G.vexnum; i++ ) visited[i]=0;
for( i=0; i<G.vexnum; i++ )
if( visited[i]==0 ) dfs(G,i,visited );
}
void dfs(Graph G,int i,int visited[]){
visit(i);//一个很简单的函数调用
visited[i]=1;
for(w=FirstAdjVex(G,i);w;w=NextAdjVex(G,i,w))
if(visited[w]==0) dfs(G,w,visited);
}
9.3.2广度优先遍历
“先被访问的顶点的邻接点” 先于 “后被访问的顶点的邻接点”被访问
void BFSTraverse ( Graph G )
{
int i, visited[M];
for( i=0; i<G.vexnum; i++ ) visited[i]=0;
InitQueue(Q);
for(i=0; i<G.vexnum; i++)
if(!visited[i])
{
visited[i]=1; visit(i); EnQueue(Q,i);
while(!QueueEmpty(Q))
{
DeQueue(Q,u); //队头元素出队并置为u
for(w=FirstAdjVex(G,u);w;w=NextAdjVex(G,u,w))
if(!visited[w])
{ visited[w]=1;visit(w);EnQueue(Q,w); }
}
}
}
9.4图的连通性
连通:从顶点V到W有一条路径,则称V和W是连通的。
连通图:任意两个顶点都是连通的无向图。
连通分量:非连通图的每一个连通部分称连通分量。
遍历无向图时,
若为连通图,仅需从任一顶点出发,深(广)度优先搜索,便可访问到图中所有顶点。
若为非连通图,需从多个顶点出发进行搜索,
而每一次从一个新的起始点搜索得到的序列恰为各个连通分量中的顶点集。
例题:
若无向连通图G=(V,E)中有7个顶点,则图G中的边的个数最少是______。
A.6 B.15 C.16 D.21
答案:A
例题:
下列关于无向连通图的叙述中,正确的是______。
Ⅰ.所有顶点的度之和为偶数 Ⅱ.边数大于顶点个数减1 Ⅲ.至少有一个顶点的度为1
A.Ⅰ B.Ⅱ C.Ⅰ和Ⅱ D.Ⅰ和Ⅲ
答案:A
因为无向连通图每一条边都被算了2次
9.5图的生成树
一连通图的生成树:
是一个极小连通子图 ;
含有图中的全部顶点(n个顶点);
但只有足以构成一棵树的n-1条边。
若一个图有n个顶点,e条边:
e<n-1,非连通图 ;
e>n-1,一定有环 ;
e=n-1,可能是生成树,但不一定。
深度遍历:
广度遍历:
非连通图的生成森林:非连通图每个连通分量的生成树一起组成非连通图的生成森林。
一个图可以有许多棵不同的生成树,所有生成树具有以下共同特点:
生成树的顶点个数与图的顶点个数相同 ;
生成树是图的极小连通子图 ;
一个有n个顶点的连通图的生成树有n-1条边;
生成树中任意两个顶点间的路径是唯一的 ;
在生成树中再加一条边必然形成回路。
9.6最小生成树
在可能的线路中选择n-1条,把所有城市(顶点)均连起来,且总耗费(各边权值之和)最小。
9.6.1普里姆(Prim)算法
要记录从顶点集U到V-U的代价最小的边的权值,引入一辅助数组;
过程:
1、选择起始顶点V1;
2、辅助数组记录起始顶点V1到其余顶点边上的权值,即邻接矩阵中的第一行 ;
3、选择辅助数组中记录的权值最小的边,边的另一顶点Vi加入集合U; 根据与Vi相关的边上的权值修改辅助数组 ;
4、重复n-1次,直到集合U中包含了n个顶点。
struct{
VertexType adjvex;
VRType lowcost; //边上的权
}closedge[MAX_VERTEX_NUM];
void MiniSpanTree_PRIM(Graph G, VerType u ) {
struct{
VertexType adjvex;//每个顶点
VRType lowcost;
}closedge[MAX_VERTEX_NUM];
k=LocateVex(G,u); //从第u个顶点开始构造最小生成树
for(j=0;j<G.vexnum;++j)//j是数组下标,顶点是k
if(j!=k) closedge[j]={u,G.arcs[k][j].adj};
closedge[k].lowcost=0; //U={u}
for(i=1;i<G.vexnum;++i)
{
k=minimum(closedge);
printf( closedge[k].adjvex, G.vexs[k] );
closedge[k].lowcost=0; //顶点k并入集合U
//比较当前结点i的每一个邻接点的权值,谁最小,谁就是下一个遍历点
for( j=0; j<G.vexnum; ++j )
if( G.arcs[k][j].adj < closedge[j].lowcost )
closedge[j]={ G.vexs[k],G.arcs[k][j].adj };
}
}
算法评价:T(n)=O(n²) ,与边数无关,适合求稠密网的MST
9.6.2克鲁斯卡尔(Kruskal)算法
在E中选取代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中;
否则,舍去此边,选取下一条代价最小的边。
关节点:
删除顶点v以及和v相关联的边之后,将图的一个连通分量分成两个或两个以上的连通分量。
重连通图:
一个没有关节点的连通图称为重连通图。