找回密码
 立即注册
首页 业界区 业界 重生之数据结构与算法----图的遍历

重生之数据结构与算法----图的遍历

陶田田 2025-6-4 21:42:55
简介

上文讲到,图的本质是多叉树。因此主要遍历方式还是DFS与BFS。
唯一的区别在于,树结构中不存在环,而图中可能回成环。因此我们需要记录一下已经访问过的节点,避免死循环。
深度优先遍历(DFS)

遍历所有节点
  1.         /// <summary>
  2.         /// 邻接表实现DFS
  3.         /// </summary>
  4.         /// <param name="startIndex"></param>
  5.         public void DFSTraverse(int startIndex)
  6.         {
  7.             if (startIndex < 0 || startIndex >= _graph.Count)
  8.                 return;
  9.             //记录一下已经访问过的,避免死循环
  10.             if (_visited[startIndex])
  11.                 return;
  12.             _visited[startIndex] = true;
  13.             //前序遍历
  14.             Console.WriteLine($"index={startIndex}");
  15.             if (_graph[startIndex]?.Count > 0)
  16.             {
  17.                 foreach (var item in _graph[startIndex])
  18.                 {
  19.                     DFSTraverse(item.Indegree);
  20.                 }
  21.             }
  22.             //后序遍历
  23.             //Console.WriteLine($"index={index}");
  24.         }
  25.                 /// <summary>
  26.         /// 邻接矩阵实现DFS
  27.         /// </summary>
  28.         /// <param name="startIndex"></param>
  29.         public void DFSTraverse(int startIndex)
  30.         {
  31.             //记录一下已经访问过的,避免死循环
  32.             if (_visited[startIndex])
  33.                 return;
  34.             _visited[startIndex] = true;
  35.             //前序遍历
  36.             Console.WriteLine($"index={startIndex}");
  37.             for (int i = 0; i < _visited.Length; i++)
  38.             {
  39.                 //为0代表未使用
  40.                 if (_matrix[startIndex, i] == 0)
  41.                     continue;
  42.                 DFSTraverse(i);
  43.             }
  44.             //后序遍历
  45.             //Console.WriteLine($"index={index}");
  46.         }
复制代码
可以看到,与多叉树的深度优先并无区别,就多了一个数组。
遍历所有路径

在树结构中,遍历所有路径和遍历所有节点,是没区别的。因为根节点到叶节点的过程是单向,所以他们之间的路径是唯一的。
但在图中,因为环的存在。所以从根节点到叶节点的过程路径会有很多种。因此在图的遍历中,图的路径需要穷举。
1.png

以此图为例,0节点到4节点,就有5种路径。
find path:0=>1=>2=>3=>4
find path:0=>1=>3=>4
find path:0=>1=>4
find path:0=>3=>4
find path:0=>4
对于图来说,由起点stc到目标节点dest的路径很多,我们需要一个onPath数组,在进入节点时标记正在访问,退出节点时撤销标记。这样就能形成一个完整的遍历路径。
  1.         public void Traverse(int src,int dest)
  2.         {
  3.             if (src < 0 || src >= _graph.Count)
  4.                 return;
  5.             //防止形成死循环
  6.             if (_visited[src])
  7.                 return;
  8.             
  9.             _visited[src] = true;
  10.             //在前序位置加入遍历路径
  11.             _path.AddLast(src);
  12.             if (src == dest)
  13.             {
  14.                 Console.WriteLine($"find path:{string.Join("=>", _path)}");
  15.             }
  16.             foreach (var item in _graph[src])
  17.             {
  18.                 Traverse(item.Indegree, dest);
  19.             }
  20.            
  21.             _path.RemoveLast();
  22.             //在后序位置撤销标记
  23.             _visited[src] = false;
  24.         }
复制代码
为什么要在后序位置撤销标记?如果不撤销。就类似遍历所有节点一样。遇到了重复节点就退出了,而漏掉了其它可能的路径。因此当节点退出时撤销标记。再往右探测可能的路径。直到遍历完整个图。
广度遍历优先(BFS)

同理可得,对于图的BFS算法。也只要加入一个visited数组来避免死循环即可。
理论上BFS遍历也需要遍历完所有节点与所有路径,但一般情况下,BFS只用来寻找最短路径。因为BFS算法是以层位维度,一层一层的搜索。第一次遇到的目标节点,那必然是最短路径。
  1.         public void BFSTraverse(int startIndex)
  2.         {
  3.             Queue<int> queue=new Queue<int>();
  4.             queue.Enqueue(startIndex);
  5.             //标记节点已被访问,避免死循环。
  6.             _visited[startIndex]=true;
  7.             while (queue.Count > 0)
  8.             {
  9.                 var cur=queue.Dequeue();
  10.                 Console.WriteLine($"cur:{cur}");
  11.                 foreach (var e in _graph[cur])
  12.                 {
  13.                     //已经访问过了就不再访问
  14.                     if (!_visited[e.Indegree])
  15.                     {
  16.                         queue.Enqueue(e.Indegree);
  17.                         _visited[e.Indegree] = true;
  18.                     }
  19.                 }
  20.             }
  21.         }
复制代码
剩下的两种,记录所在层与记录权重。不在赘述,可以参考多叉树的BFS三种遍历代码。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册