引子(一些图的基本操作)
不要求掌握代码,仅供抽象的考虑
- Adjacent(G,x,y):判断G是否存在边<x,y>或(x,y)
- Neighbors(G,x):列出与结点x相邻的边
- InsertVertex(G,x):插入结点x
- DeleteVertex(G,x):删除结点
- AddEdge(G,x,y):添加边
- RemoveEdge(G,x,y):删除边
- FirstNeighbor(G,x):找与顶点x相连接的第一个结点,return值为顶点编号或者-1
- NextNeighbor(G,x):相邻结点的相邻结点,具体同上
- GetEdgeValue(G,x,y):获取结点x&y之间的边的权值
- SetEdgeValue(G,x,y,v):设置结点x&y之间的边的权值
广度优先遍历(BFS)
对比树:
相同:相当于层序遍历(使用队列横向寻找)
区别:图会构成环路,所以访问时有的结点可能会被重复访问
代码:
以无向图、邻接表存储方法为基础的BFS(省略队列的Init,EnQueue,DeQueue,isEmpty函数)
bool visited[Vmax]; //判断结点是否被访问
void visit(int v); //访问结点
void BFSTraverse(ALGragh G){
for(int i = 0;i<G.vexnum;i++) //初始化结点全部未被访问
visited[i] = false;
InitQ(Q); //初始化队列
for(int j = 0;j<G.vexnum;j++) //访问非连通图所有结点
if(!visited[i])
BFS(G,i);
}
void BFS(ALGragh G,int v){ //广度优先遍历一个连通图
visit(v);
visited[v] = true;
EnQueue(Q,v);
while(!isEmpty(Q)){
DeQueue(Q,v);
int w;
for(w = FirstNeighbor(G,v);w>=0;w = NextNeighbor(G,v,w))
if(!visited[w]){
visit(w);
visited[w] = true;
EnQueue(Q,w);
}
}
}
性质:
- 邻接矩阵存储的图BFS是一定的,但是邻接表存储的图不是一定的
- 对于有向图:不是从每一个结点开始访问都可以遍历
性能分析:
- 空间复杂度:最坏是O(|V|),最好O(1)【答最坏】
- 时间复杂度:邻接矩阵法:O(|V|2)
邻接表法:O(|V|+|E|)
广度优先生成树(森林):
遍历过程中得到的遍历树
邻接矩阵存储的图广度优先生成树是一定的,但是邻接表存储的图广度优先生成树不是一定的
BFS求最短路径问题:
深度优先遍历(DFS)
对比树:
相同:相当于先序遍历(使用栈或者递归思想纵向寻找)
区别:图会构成环路,所以访问时有的结点可能会被重复访问
代码:
以无向图、邻接表存储方法为基础的BFS,采用递归思想
bool visited[Vmax]; //判断结点是否被访问
void visit(int v); //访问结点
void DFSTraverse(ALGragh G){
for(int i = 0;i<G.vexnum;i++) //初始化结点全部未被访问
visited[i] = false;
for(int j = 0;j<G.vexnum;j++) //访问非连通图所有结点
if(!visited[i])
DFS(G,i);
}
void DFS(ALGragh G,int v){ //深度优先遍历一个连通图
visit(v);
visited[v] = true;
int w;
for(w = FirstNeighbor(G,v);w>=0;w = NextNeighbor(G,v,w))
if(!visited[w])
DFS(G,w);
}
性质:
- 邻接矩阵存储的图DFS是一定的,但是邻接表存储的图不是一定的
性能分析:
- 空间复杂度:最坏是O(|V|),最好O(1)【答最坏】
- 时间复杂度:邻接矩阵法:O(|V|2)
邻接表法:O(|V|+|E|)
深度优先生成树(森林):
遍历过程中得到的遍历树
邻接矩阵存储的图深度优先生成树是一定的,但是邻接表存储的图深度优先生成树不是一定的
图的遍历与图的连通性
无向图
调用DFS/BFS函数次数等于连通分量数
对于连通图只调用一次
有向图
与起始结点能否直接找到其他结点有关,需要具体分析问题