图的遍历 Graph: Traverse

Traverse

通常有两种方式:

  • 广度优先搜索(BFS,Breadth-First-Search)
  • 深度优先搜索(DFS,Depth-First-Search)

1 BFS

1.1 Explanation

这是一种层次遍历的方法,可以通过队列这种数据结构来实现,每次向前走一步访问新的一批顶点:

  • 首先我们需要一个标记数组visited[MAX_VEX]以及一个辅助队列queue
  • 然后我们可以按顶点标号顺序开始访问,先将标号第一个顶点入队,以这个顶点为起点开始进行广度优先搜索:按顺序将这个顶点的未访问的邻接顶点入队后,将这个顶点出队,重复这个操作直到队列为空为止,即完成以这个顶点为起点的广度优先搜素
  • 继续对下一个顶点进行广度优先搜索,首先判断这个顶点是否已经被访问过,如果没有,进行广度优先搜索,如果已经访问,则继续看下一个顶点直到最后一个顶点已经被访问过了(考虑图可能不是连通图,含有多个连通分量,因此我们必须对每个顶点都看一次,因为即使只有一个顶点也可能会是一个连通分量)

最终,我们便完成了广度优先搜索通过广度优先搜索可以找到从某个顶点出发到达其他顶点的最短路径(即单源最短路径)

1.2 Performance

根据存储结构不同,广度优先搜索的性能不同:

  • 邻接表: O ( ∣ V ∣ + ∣ E ∣ ) O(|V|+|E|) O(V+E),即每个顶点访问一次,每条边至少访问一次
  • 邻接矩阵: O ( ∣ V ∣ 2 ) O(|V|^{2}) O(V2),即邻接矩阵遍历的复杂度

2. DFS

2.1 Definition

通过一个辅助栈可以实现深度优先搜索

  • 同样还需要一个标记数组
  • 按顶点序号入栈,将标号第一个顶点入栈,然后继续找这个顶点标号最前的邻接顶点入栈,重复这个操作直到当前顶点的邻接顶点都已经访问过为止,这时逐步退栈,对栈顶顶点重复上述操作,直到栈退至空,即完成以第一个顶点的深度优先搜索
  • 同样还需要对第二个顶点继续做以上操作,直到所有顶点已经访问为止

最终我们便完成了图的深度优先搜索

2.2 Performance

同样根据存储结构不同:

  • 邻接链表: O ( ∣ V ∣ + ∣ E ∣ ) O(|V|+|E|) O(V+E)
  • 邻接矩阵: O ( ∣ V ∣ 2 ) O(|V|^{2}) O(V2)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * (有向)的深度优先遍历算法模板 */ package dsa; public abstract class DFS extends GraphTraverse { //变量 protected static int clock = 0;//遍历过程中使用的计时钟 //构造方法 public DFS(Graph g) { super(g); } //深度优先遍历算法 protected Object traverse(Vertex v, Object info) {//从顶点v出发,做深度优先查找 if (UNDISCOVERED != v.getStatus()) return null;//跳过已访问过的顶点(针对非连通) v.setDStamp(clock++); v.setStatus(DISCOVERED); visit(v, info);//访问当前顶点 for (Iterator it = v.outEdges(); it.hasNext();) {//检查与顶点v Edge e = (Edge)it.getNext();//通过边e = (v, u) Vertex u = (Vertex)e.getVPosInV(1).getElem();//相联的每一顶点u switch (u.getStatus()) {//根据u当前的不同状态,分别做相应处理 case UNDISCOVERED ://若u尚未被发现,则 e.setType(TREE);//e被归类为“树边” traverse(u, info);//从u出发,继续做深度优先查找 break; case DISCOVERED ://若u已经被发现,但对其访问尚未结束,则 e.setType(BACKWARD);//将e归类为“后向跨边” break; default ://VISITED,即对u的访问已经结束 if (u.getDStamp() < v.getDStamp())//若相对于v,u被发现得更早,则 e.setType(CROSS);//将e归类为“横跨边” else//否则 e.setType(FORWARD);//将e归类为“前向跨边” break; } }//至此,v的所有邻居都已访问结束,故 v.setFStamp(clock++); v.setStatus(VISITED);//将v标记为VISITED return null;//然后回溯 } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值