===================================================
一、无向图的连通分量和生成树
在对无向图进行遍历时,对于连通图,仅需从图中任一顶点出发,进行深度优先搜索或广度优先搜索,即可访问到图中所有顶点。
对非连通图,则需从多个顶点出发进行搜索,而每一次从一个新的起始点出发进行搜索的过程中得到的顶点访问序列恰为其各个连通分量的顶点集。
假设E(G)为连通图G中所有边的集合。则从图中任一顶点出发遍历图时,必定将E(G)分成两个集合T(G)和B(G)。
T(G)是遍历图过程中历经的边的集合。显然T(G)和图G中所有顶点一起构成了连通图G的极小连通子图。
并且这是连通图的一棵生成树,并且称由深度优先搜索得到的为深度优先生成树。由广度优先搜索得到的为广度优先生成树。
对于非连通图,每个连通分量中的顶点集,和遍历时走过的边一起构成若干棵生成树,这些连通分量的生成树,组成非连通图的生成森林。
假设以孩子兄弟链表作为生成森林的存储结构,其代码如下:
1 void DFSForest(Graph G, CSTree &T) { 2 //建立无向图G的深度优先生成森林的孩子兄弟链表T 3 T = NULL; 4 for(v=0;v<G.vexnum; ++v) 5 visited[v] = FALSE; 6 for(v=0; v<G.vexnum; ++v) 7 if(!visited[v]) { //第v个顶点为新的生成树的根结点 8 p = (CSTree) malloc (sizeof(CSNode)); //分配根结点 9 * p = { GetVex(G, v), NULL, NULL}; //给该结点赋值 10 if(!T) T = p; //是第一棵生成树的根(T的根) 11 else q->nextsibling = p; //是其他生成树的根 12 q = p; //q指向当前生成树的根 13 DFSTree(G, v, p); //建立以p为根的生成树 14 } 15 } 16 17 void DFSTree(Graph G, int v, CSTree &T) { 18 //从第v个顶点出发深度优先遍历图G,建立以T为根的生成树。 19 visited[v] = TRUE; 20 first = TRUE; 21 for(w=FirstAdjVex(G,v); w>=0; w=NextAdjVex(G, v, w)) 22 if(!visited[w]) { 23 p = (CSTree) malloc (CSNode); //分配孩子结点 24 * p = {GetVex(G, w), NULL, NULL}; 25 if (first) { 26 T ->lchild = p; first = FALSE; 27 } 28 else { 29 q ->nextsibling = p; 30 } 31 q = p; 32 DFSTree(G, w, q); 33 } 34 35 }
===================================================
二、有向图的强连通分量
===================================================
三、最小生成树
假设要在n个城市之间建立通信联络网,则连通n个城市只需要n-1条铁路。
这时,自然会考虑这样一个问题,如何在最节省经费的前提下建立这条通信网。
在n个城市之间,最多可能设置n(n-1)/2条线路,那么,如何在这些可能的线路中选择n-1条,使得总费用最小。
由此可以用连通图来表示n个城市以及n个城市间可能设置的通信线路。
其中网的顶点表示城市,边表示两城市之间的线路。 赋予边的权值表示相应的代价。
这个问题就是构造连通网的最小代价生成树(简称:最小生成树)问题。
普利姆算法、克鲁斯卡尔算法;
===================================================
四、关节点和重连通分量
假若在删去顶点v以及和v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连通分量。
则称顶点v为该图的关节点。
一个没有关节点的连通图称为是重连通图。
若在连通图上至少删去k个顶点才能破坏图的连通性,则称此图的连通度为k。
关节点和重连通在实际中有较多应用。