• 深度优先搜索遍历与广度优先搜索遍历


    目录

    一.深度优先搜索遍历

    1.深度优先遍历的方法

    2.采用邻接矩阵表示图的深度优先搜索遍历

    3.非连通图的遍历

    二.广度优先搜索遍历

    1.广度优先搜索遍历的方法

    2.非连通图的广度遍历

    3.广度优先搜索遍历的实现

    4.按广度优先非递归遍历连通图


    一.深度优先搜索遍历

    1.深度优先遍历的方法

    从图中一个未访问的顶点V开始,沿着一条路一直走到底,如果到达这条路尽头的节点 ,则回退到上一个节点,再从另一条路开始走到底…,不断递归重复此过程,直到所有的顶点都遍历完成。

    以下面无向图为例,2为起点

    (1)以2为起点访问1

    (2)以1为起点,因为“1”和“2”之间的边已经走过,所以走3

    (3) 同理,以3为起点访问5

    (4)到5后,没有可访问的点,返回3,3也没有可访问的点,到1后,可访问之前没有访问过的4

    (5)4访问6,至此,遍历完所有的点,DFS(深度优先搜索遍历):2->1->3->5->4->6

     2.采用邻接矩阵表示图的深度优先搜索遍历
    1. #define MAX_VERTEX_NUM 100
    2. typedef struct {
    3. // 定义图的相关信息
    4. int vexnum; // 顶点数
    5. int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵
    6. // 其他成员...
    7. } AMSGraph;
    8. bool visited[MAX_VERTEX_NUM]; // 记录顶点是否被访问过
    9. void DFS(AMSGraph G, int v)
    10. {
    11. cout << v;
    12. visited[v] = true;
    13. for (int w = 0; w < G.vexnum; w++) {
    14. if (G.arcs[v][w] == 1 && !visited[w]) {
    15. DFS(G, w);
    16. }
    17. }
    18. }

    http://t.csdn.cn/HmcOt

    之前的一篇文章已经详细说明了邻接矩阵和邻接表的区别,这里同理

    1.用邻接矩阵表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,时间复杂度O(n^{2})

    2.用邻接表表示图,虽然有2e个表结点,但只需扫描e个结点即可完成遍历,加上访问n个头结点的时间,时间复杂度为O(n+e)

    稠密图适于在邻接矩阵上进行深度遍历;

    稀疏图适于在邻接表上进行深度遍历。

    3.非连通图的遍历

    左边的连通分量进行深度优先搜索遍历,再在b,g之中选择一个点进行深度优先搜索遍历

    其中一种合理的顶点访问次序为:

    a,c,h,d,f,k,e,b,g

    二.广度优先搜索遍历

    1.广度优先搜索遍历的方法

    从某个顶点V出发,访问该顶点的所有邻接点V1,V2..VN,从邻接点V1,V2...VN出发,再访问他们各自的所有邻接点,重复上述步骤,直到所有的顶点都被访问过

    以如下图为例,起点为V1

     一层一层进行访问,广度优先搜索遍历的结果为:V1->C2->V3->V4->V5->V6->V7->V8

    2.非连通图的广度遍历

    与连通图类似,在b,g中任意选择一个点开始 

    合理的顶点访问次序为:a->c->d->e->f->h->k->b->g

     

    3.广度优先搜索遍历的实现

    广度优先搜索遍历的实现,与树的层次遍历很像,可以用队列进行实现(出队一个结点,将他的邻接结点入队)

    以下动图来自爱编程的西瓜,方便大家理解遍历过程

    4.按广度优先非递归遍历连通图
    1. #include <iostream>
    2. using namespace std;
    3. const int MAX_SIZE = 100; // 队列的最大容量
    4. const int MAX_VERTICES = 100; // 图的最大顶点数
    5. struct Queue {
    6. int data[MAX_SIZE];
    7. int front; // 队头指针
    8. int rear; // 队尾指针
    9. };
    10. struct Graph { // 定义图
    11. bool edges[MAX_VERTICES][MAX_VERTICES]; // 邻接矩阵
    12. int numVertices; // 实际顶点数
    13. };
    14. void InitQueue(Queue& Q) {
    15. Q.front = 0;
    16. Q.rear = -1;
    17. }
    18. bool EnQueue(Queue& Q, int x) {
    19. if (Q.rear == MAX_SIZE - 1) {
    20. // 队列已满,无法插入
    21. return false;
    22. }
    23. Q.data[++Q.rear] = x;
    24. return true;
    25. }
    26. bool DeQueue(Queue& Q, int& x) {
    27. if (Q.front > Q.rear) {
    28. // 队列为空,无法出队
    29. return false;
    30. }
    31. x = Q.data[Q.front++];
    32. return true;
    33. }
    34. bool QueueEmpty(Queue& Q) {
    35. return Q.front > Q.rear;
    36. }
    37. // 找到顶点u的第一个邻接点并返回
    38. int FirstAdjVex(Graph& G, int u) {
    39. for (int v = 0; v < G.numVertices; ++v) {
    40. if (G.edges[u][v]) {
    41. return v;
    42. }
    43. }
    44. return -1; // 或者返回一个特殊的值表示找不到邻接点
    45. }
    46. // 找到图 G 中顶点 u 相对于顶点 w 的下一个邻接点并返回
    47. int NextAdjVex(Graph& G, int u, int w) {
    48. for (int v = w + 1; v < G.numVertices; ++v) {
    49. if (G.edges[u][v]) {
    50. return v;
    51. }
    52. }
    53. return -1; // 或者返回一个特殊的值表示找不到下一个邻接点
    54. }
    55. void BFS(Graph G, int v) {
    56. cout << v;
    57. bool visited[MAX_VERTICES] = { false };
    58. visited[v] = true; // 访问第v个顶点
    59. Queue Q;
    60. InitQueue(Q);
    61. EnQueue(Q, v); // v进队
    62. while (!QueueEmpty(Q)) {
    63. int u;
    64. DeQueue(Q, u); // 队头元素出队并置为u
    65. for (int w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w)) {
    66. if (!visited[w]) { // w为u的尚未访问的邻接点
    67. cout << w;
    68. visited[w] = true;
    69. EnQueue(Q, w); // w进队(将访问的每一个邻接点入队)
    70. }
    71. }
    72. }
    73. }

    广度优先搜索遍历算法的效率

    1.如果使用邻接矩阵,则BFS对于每一个被访问到的顶点,都要循环检测矩阵中的整整一行,时间复杂度为O(n^{2})

    2.用邻接表来表示图,虽然有2e个表结点,但只需扫描e个结点即可完成遍历,加上访问n个头结点的实践,时间复杂度为O(n+e)
     

     深度优先搜索遍历(DFS)广度优先搜索遍历(BFS)算法的效率

    1.空间复杂度相同,都是O(n)(借用了堆栈或队列)

    2.时间复杂度只与存储结构(邻接矩阵【O(n^{2})】或邻接表【O(n+e)】)有关,而与搜索路径无关

  • 相关阅读:
    【云原生之kubernetes实战】kubernetes集群的检测工具——popeye
    基于Java+Spring+mybatis+vue+element实现酒店管理系统
    解决vs code终端无法执行命令的问题
    前端list.push,封装多个对象
    DNSPod十问党霏霏:充电桩是披着高科技外皮的传统基建?
    maven依赖管理
    程序员是职业病高发群体,别天真的以为只有秃头那么简单,才不是呢。
    vue3的7种路由守卫使用大全
    【CSDN Daily Practice】【贪心】文本左右对齐
    SpringBoot+Vue项目在线学习网站
  • 原文地址:https://blog.csdn.net/weixin_69884785/article/details/132639776