• 学习伪代码(这点不是硬性要求,可以直接用 Golang 实现)
  • 基本定义和相关概念
  • 数据结构的逻辑实现(邻接矩阵实现,邻接表实现)
  • 数据结构和算法的代码实现(这里使用 Golang BFS + DFS)
  • 用邻接表建立一个表,并用深度优先算法和广度优先算法来遍历途中的每个节点

Concept

图的相关基本概念来自于维基百科,从离散数学的角度解释了这些概念。图有多种变体,包括简单图、多重图、有向图、无向图等,但大体上有以下两种定义方式。

一张Graph - 图1 是一个二元组 Graph - 图2Graph - 图3,其中 Graph - 图4Graph - 图5称为顶点集,Graph - 图6 称为边集。它们亦可写成 Graph - 图7Graph - 图8Graph - 图9Graph - 图10Graph - 图11的元素是一个二元组数对,用 Graph - 图12Graph - 图13表示,其中 Graph - 图14

Reference

Data Structure

选择用邻接表来实现

  1. type link struct {
  2. serial int
  3. weight int
  4. next *link
  5. }
  6. // Graph -
  7. type Graph []*link

Build

  1. // Build -
  2. func Build() Graph {
  3. var (
  4. g Graph
  5. n, e int
  6. p, q int
  7. )
  8. fmt.Scanf("%d%d", &n, &e)
  9. for i := 0; i < n; i++ {
  10. g = append(g, &link{
  11. serial: i,
  12. weight: defaultWeight,
  13. next: nil,
  14. })
  15. }
  16. for i := 0; i < e; i++ {
  17. fmt.Scanf("%d%d", &p, &q)
  18. node := &link{
  19. serial: q,
  20. weight: defaultWeight,
  21. next: g[p].next,
  22. }
  23. g[p].next = node
  24. }
  25. return g
  26. }

这个函数只建立了单向的连接,如果是一个无向图,应该怎样修改程序。

BFS

  1. // Visited -
  2. var Visited = make([]int, 100)
  3. // DFS -
  4. func DFS(g *Graph, v int) {
  5. fmt.Printf("[%d]", v)
  6. Visited[v] = 1
  7. p := (*g)[v].next
  8. for p != nil {
  9. if Visited[p.serial] == 0 {
  10. DFS(g, p.serial)
  11. }
  12. p = p.next
  13. }
  14. }

DFS

  1. // BFS -
  2. // Use Queue to store the sequences
  3. func BFS(g *Graph, v int) {
  4. fmt.Printf("[%d]", v)
  5. var (
  6. f, r int
  7. Q = make([]int, 100)
  8. )
  9. Visited[v] = 1
  10. p := (*g)[v].next
  11. for (p != nil) || (f != r) {
  12. for p != nil {
  13. if Visited[p.serial] == 0 {
  14. r++
  15. Q[r] = p.serial
  16. fmt.Printf("[%d]", p.serial)
  17. Visited[p.serial] = 1
  18. }
  19. p = p.next
  20. }
  21. if f != r {
  22. f++
  23. v = Q[f]
  24. p = (*g)[v].next
  25. }
  26. }
  27. }

如果图是一个连通的图,上面的算法没有问题,考虑非连通图图的情况,应该如何修改程序。提示:如果有孤立的子图,则不会被遍历到,得想个办法找到他们,然后从一个节点开始遍历。