7.5 深度优先算法DFS和广度优先算法BFS

    从图的某个顶点出发访问遍图中所有顶点,且每个顶点仅被访问一次。(连通图与非连通图)

    深度优先遍历(DFS);

    1、访问指定的起始顶点;

    2、若当前访问的顶点的邻接顶点有未被访问的,则任选一个访问之;反之,退回到最近访问过的顶点;直到与起始顶点相通的全部顶点都访问完毕;

    3、若此时图中尚有顶点未被访问,则再选其中一个顶点作为起始顶点并访问之,转 2; 反之,遍历结束。

    连通图的深度优先遍历类似于树的先根遍历

    如何判别V的邻接点是否被访问?

    解决办法:为每个顶点设立一个“访问标志”。首先将图中每个顶点的访问标志设为 FALSE, 之后搜索图中每个顶点,如果未被访问,则以该顶点为起始点,进行深度

    优先遍历,否则继续检查下一顶点。

    访问指定的起始顶点;若当前访问的顶点的邻接顶点有未被访问的,则任选一个访问之;

    img

    反之,退回到最近访问过的顶点;直到与起始顶点相通的全部顶点都访问完毕;

    回退到1,发现了新的没有被访问的结点

    img

    继续回退,回退到0

    img

    顶点的访问序列为: v0 , v1 , v4 , v5 , v6 , v2 , v3(不唯一)

    实现过程:依靠栈,一维数组和图的邻接矩阵存储方式

    图的邻接矩阵存储方式

    img

    使用一个一维数组存储所有的顶点,对应的下标的元素为1(代表已经被访问),0(代表没有被访问)

    先访问 v1,0进栈,0处置为1

    img

    继续访问 v2,1进栈,1处置为1

    继续访问v4(依据邻接矩阵),3入栈,3处置为1

    img

    继续访问 v8,7入栈,7处置为1

    继续访问 v5,4入栈,4处置为1

    继续访问,发现没有还没访问的结点了,那么好,退栈(也就是回退)开始,回退到 v1处,也就是0的时候,发现了没有被访问的结点,那么继续访问之

    img

    继续访问 v3,2进栈,2处置为1,继续访问v6,5进栈,5处置为1,继续访问v7,6进栈,6处置为1

    发现没有还没被访问的结点了,那么好,继续回退(也就是退栈的过程)

    img

    一直到栈空,说明深度优先搜索完毕。结束程序。

    遍历图的过程实质上是对每个顶点查找其邻接点的过程,所耗费的时间取决于所采用的存储结构。 对图中的每个顶点至多调用1次DFS算法,因为一旦某个顶点已访问过,则不再从它出发进行搜索。

    邻接链表表示:查找每个顶点的邻接点所需时间为O(e),e为边(弧)数,算法时间复杂度为O(n+e)

    数组表示:查找每个顶点的邻接点所需时间为O(n2),n为顶点数,算法时间复杂度为O(n2)

    代码如下

    广度优先搜索(BFS)

    方法:从图的某一结点出发,首先依次访问该结点的所有邻接顶点 Vi1, Vi2, …, Vin 再按这些顶点被访问的先后次序依次访问与它们相邻接的所有未被访问的顶点,重复此过程,直至所有顶点均被访问为止。

    顶点的访问次序

    img

    实现过程:依靠队列和一维数组来实现

    1. 2 #include<queue>
    2. 3 using namespace std;
    3. 4
    4. 5 const int MAX = 10;
    5. 6 //辅助队列的初始化,置空的辅助队列Q,类似二叉树的层序遍历过程
    6. 7 queue<int> q;
    7. 8 //访问标记数组
    8. 9 bool visited[MAX];
    9. 10 //图的广度优先搜索算法
    10. 11 void BFSTraverse(Graph G, void (*visit)(int v))
    11. 12 {
    12. 13 int v = 0;
    13. 14 //初始化访问标记的数组
    14. 15 for (v = 0; v < G.vexnum; v++)
    15. 17 visited[v] = false;
    16. 19 //依次遍历整个图的结点
    17. 20 for (v = 0; v < G.vexnum; v++)
    18. 21 {
    19. 22 //如果v尚未访问,则访问 v
    20. 23 if (!visited[v])
    21. 24 {
    22. 25 //把 v 顶点对应的数组下标处的元素置为真,代表已经访问了
    23. 26 visited[v] = true;
    24. 27 //然后v入队列,利用了队列的先进先出的性质
    25. 28 q.push(v);
    26. 29 //访问 v,打印处理
    27. 30 cout << q.back() << " ";
    28. 31 //队不为空时
    29. 32 while (!q.empty())
    30. 33 {
    31. 36 q.pop();
    32. 37 //w为u的邻接顶点
    33. 38 for (int w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G,u,w))
    34. 39 {
    35. 40 //w为u的尚未访问的邻接顶点
    36. 41 if (!visited[w])
    37. 42 {
    38. 43 visited[w] = true;
    39. 44 //然后 w 入队列,利用了队列的先进先出的性质
    40. 45 q.push(w);
    41. 46 //访问 w,打印处理
    42. 47 cout << q.back() << " ";
    43. 48 }//end of if
    44. 49 }//end of for
    45. 50 }//end of while
    46. 51 }//end of if
    47. 53 }