图的遍历
遍历是指:找每个顶点的邻接点
图中存在回路,图的任意顶点都可能与其他顶点相同,
在访问完某个顶点后可能会沿着某些边又 回到了曾经访问过的结点
解决思路:设置辅助数组visited[n],用来标记每个被访问过的顶点
初始状态visited[i] = 0;
顶点被访问,改visited[i] = 1,防止被多次访问
深度优先搜索DFS
void DFS(AMGraph G, int v){
//图G为邻接矩阵v所在的行
cout<<v;
visited[v] = true; //访问第v个顶点
for(w = 0; w < G.vexnum; w++)//一次检查邻接矩阵v所在的行
if((G.arcs[v][w] != 0) && (!visited[w]))
DFS(G,w); //w是v的邻接点,if w未访问,则厉鬼调用DFS
}
用邻接矩阵来表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,O(n*n)
用邻接表来表示,虽然有2e个表结点,但只需要扫描e个结点即可完成遍历,
加上访问n个头结点的的时间,O(n+e)
广度优先遍历BFS
void BFS(Graph G, int v){
//按广度优先非递归遍历连通图G
cout<<v;
visited[v] = true; //访问第v个顶点
InitQueue(Q); //辅助队列Q初始化,置空
EnQueue(Q,v); //v入队
while(!QueueEmpty(Q)){
//队列非空
DeQueue(Q,u); //队头元素出队并置为u
for(w = FirstAdjVex(G,u); w >= 0; w = NextAdjVex(G, u, w))
if(!visited[w]){
//w为u的尚未访问的邻接顶点
cout<<w;
visited[w] = true;
EnQueue(Q,w); //w入队
}//if
}//while
}//BFS
如果使用邻接矩阵,BFS对于每一个被访问到达顶点,
都要循环检测矩阵中的整整一行(n个),O(n*n)
邻接表,虽然有2e个表结点,但只需扫描e个结点即可完成遍历,
加上n给头结点,O(n+e)
DFS和BFS的算法效率比较:
空间复杂度相同,O(n)
时间复杂度只与存储结构(邻接矩阵或邻接表)相关,而与搜索路径无关
************************************************
生成树:所有顶点均由边连接在一起,但不存在回路的图
生成树顶点个数图的顶点个数相同,是图的极小连通子图
n-1条边
生成树中任意两点间的路径唯一
无向图的生成树
生成树:所有顶点均由边连接在一起,但不存在回路的图
生成树顶点个数图的顶点个数相同,是图的极小连通子图
n-1条边
生成树中任意两点间的路径唯一
最小生成树:给定一个无向网络,在该网的所有生成树中,
各边权值之和最小的生成书称为最小生成树
(n个地点建立通信网)
MST
构造最小生成树的算法
Prim算法
每次去找一个权值最小的顶点
Kruskal算法
如果遇到矛盾,就可以有两个最小生成树(即有时MST不唯一)
实际应用:最短路径
单源最短路径Dijkstra
所有顶点间的最短路径Floyd
Dijkstra
按路径长度递增次序产生最短路径
由于xxx的加入,到别的点的路径有没有变小
所有顶点间的最短路径,还可以用Dijkstra求n次,O(n*n*n)
Floyd
逐个顶点试探,从Vi到Vj中所有可能存在的路径中,选出提条长度最短的路径
************************************************
有向无环图:无环的有向图,DAG图 (前置课程表)
AOV拓扑排序 AOE关键路径
AOV:
AOV不允许有回路
一个AOV网的拓扑序列不唯一
检测AOV中是否存在环的方法:
对有向图构造其顶点的拓扑有序序列,
若网中所有顶点都在他的拓扑有序序列中,
则该AOV网必定不存在环
AOE关键路径: