返回

深度探索图的遍历:广度优先与深度优先可视化实现

闲谈

图是一种强大的数据结构,在许多计算机科学应用程序中都有广泛应用。遍历图涉及系统地访问图中的所有节点和边。本文将介绍两种经典的图遍历算法:广度优先搜索(BFS)和深度优先搜索(DFS),并提供使用 EasyX 库在 C++ 中实现这些算法的可视化演示。

广度优先搜索(BFS)

BFS 以逐层方式遍历图,从根节点开始,依次访问其所有相邻节点,然后再继续访问下一层。使用队列数据结构,BFS 确保优先遍历图的宽度,而不是深度。

void bfs(Graph& graph, int root) {
  // 初始化队列并入队根节点
  queue<int> q;
  q.push(root);

  // 标记已访问节点
  vector<bool> visited(graph.size(), false);
  visited[root] = true;

  // 队列不为空,继续遍历
  while (!q.empty()) {
    // 出队队首节点
    int u = q.front();
    q.pop();

    // 访问节点 u
    // ...

    // 遍历 u 的所有相邻节点
    for (auto v : graph[u]) {
      if (!visited[v]) {
        // 如果 v 未被访问,则入队 v
        q.push(v);

        // 标记 v 为已访问
        visited[v] = true;
      }
    }
  }
}

深度优先搜索(DFS)

DFS 沿着图的深度进行遍历,从根节点开始,深入探索一条路径,直到遇到死路,然后再回溯到上一个未探索的分支。使用栈数据结构,DFS 优先遍历图的深度,而不是宽度。

void dfs(Graph& graph, int root) {
  // 初始化栈并压入根节点
  stack<int> s;
  s.push(root);

  // 标记已访问节点
  vector<bool> visited(graph.size(), false);
  visited[root] = true;

  // 栈不为空,继续遍历
  while (!s.empty()) {
    // 弹出栈顶节点
    int u = s.top();
    s.pop();

    // 访问节点 u
    // ...

    // 遍历 u 的所有相邻节点
    for (auto v : graph[u]) {
      if (!visited[v]) {
        // 如果 v 未被访问,则压栈 v
        s.push(v);

        // 标记 v 为已访问
        visited[v] = true;
      }
    }
  }
}

可视化实现

使用 EasyX 库,我们可以创建交互式可视化界面,直观地显示图的遍历过程。用户可以通过单击按钮选择 BFS 或 DFS 算法,然后观察图中的节点和边的遍历顺序。

int main() {
  // 创建 EasyX 窗口
  initgraph(640, 480);

  // 初始化图
  Graph graph;
  // ...

  // 主循环
  while (true) {
    // 绘制图
    draw_graph(graph);

    // 等待用户输入
    char key = getch();

    // 根据用户输入执行 BFS 或 DFS
    if (key == 'b') {
      bfs(graph, 0);
    } else if (key == 'd') {
      dfs(graph, 0);
    }

    // 更新可视化
    update_visualization();
  }

  // 销毁 EasyX 窗口
  closegraph();

  return 0;
}

总结

通过结合广度优先搜索和深度优先搜索的可视化实现,本文提供了对图遍历算法的深入理解。该代码不仅易于理解和修改,还提供了一个交互式可视化界面,让用户可以亲眼见证算法的运行过程。这种动手学习体验使读者能够加深对图遍历的理解和实际编程技能。