数据结构 -- 图的广度优先遍历(BFS)

图的广度优先遍历(BFS)

bfs总是先访问完同一层的结点,然后才继续访问下一层结点,如下图 从0 ->(1、2)-> (3、4、6) -> (5) 一层一层向距离起始点更远的顶点遍历。它最有用的性质是可以遍历一次就生成中心结点到所遍历结点的最短路径,这一点在求无权图的最短路径时非常有用。
在这里插入图片描述


scala 实现

下面的代码:
1 创建一个队列,遍历的起始点放入队列,新建一个 boolean 数组
2 从队列中取出一个元素,收集它,将其标记为已访问,并将其未访问过的子结点放到队列中
3 重复2,直至队列空

GraphBFS.scala
import com.datastructure.Graph

import scala.collection.mutable.{ArrayBuffer, Queue}

class GraphBFS {
  private var G: Graph = _
  private var visited: Array[Boolean] = _
  private var order = ArrayBuffer[Int]()


  def this(g: Graph) {
    this()
    val lenth = g.getV()
    G = g
    visited = Array.ofDim[Boolean](lenth)
    for (i <- 0 until lenth) {
      if (!visited(i)) {
        bfs(i)
      }
    }
  }

  def bfs(s: Int) = {
    val queue = Queue[Int]()
    visited(s) = true
    queue.enqueue(s)
    while (!queue.isEmpty) {
      val first = queue.dequeue()
      order += first
      for (w <- G.getAdjacentSide(first)) {
        if (!visited(w)) {
          queue.enqueue(w)
          visited(w) = true
        }
      }
    }
  }

  def bfsOrder(): Array[Int] = {
    order.toArray
  }

}

object GraphBFS {
  def apply(g: Graph): GraphBFS = new GraphBFS(g)

  def main(args: Array[String]): Unit = {
    val g = Graph("./data/graph/g.txt")
    val graphBFS = GraphBFS(g)
    graphBFS.bfsOrder().foreach(println)
  }
}

// 0
// 1
// 2
// 3
// 4
// 6
// 5

Graph.scala

import java.io.File
import java.util.Scanner

import scala.collection.mutable.TreeSet

class Graph {
  var V = 0 // 顶点
  var E = 0 // 边
  var adj: Array[TreeSet[Int]] = _ // 红黑树数组

  def this(filename: String) {
    this()
    val scanner = new Scanner(new File(filename))
    V = scanner.nextInt()
    adj = Array.ofDim[TreeSet[Int]](V)
    for (i <- 0 until V) {
      adj(i) = TreeSet.empty
    }
    E = scanner.nextInt()
    for (i <- 0 until E) {
      val a = scanner.nextInt()
      val b = scanner.nextInt()
      //println(s"$a + $b")
      var as = adj(a)
      //if (as == null) as = TreeSet.empty
      as.add(b)
      adj(a) = as
      var bs = adj(b)
      //if (bs == null) bs = TreeSet.empty
      bs.add(a)
      adj(b) = bs
    }
  }

  override def toString: String = {
    val sb = new StringBuffer()
    for (i <- 0 until adj.length) {
      sb.append(s"顶点 $i ->\t")
      if (adj(i) != null) {
        for (y <- adj(i)) {
          sb.append(s"$y\t")
        }
      }
      sb.append("\n")
    }
    sb.toString
  }

  /**
   * 获得 图中顶点的个数
   *
   * @return
   */
  def getV() = {
    V
  }

  /**
   * 获得 图中边的个数
   *
   * @return
   */
  def getE() = {
    E
  }


  /**
   * 两个顶点间是否有边
   *
   * @param v
   * @param w
   * @return
   */
  def hasEdge(v: Int, w: Int) = {
    adj(v).contains(w)
  }

  /**
   * 获取v的所有邻边
   *
   * @param v
   * @return
   */
  def getAdjacentSide(v: Int) = {
    if (adj(v) != null) {
      adj(v).toList
    } else {
      List.empty
    }
  }
}

object Graph {
  def main(args: Array[String]): Unit = {
    val graph = Graph("./data/graph/g.txt")
    println(graph)

    println("-------------------------")
    println(s"顶点个数:${graph.getV()}")
    println("-------------------------")
    println(s"边的个数:${graph.getE()}")
    println("-------------------------")
    println(s"2的邻边:${graph.getAdjacentSide(2)}")
    println("-------------------------")
    println(s"1 和 2 是否有边:${graph.hasEdge(1, 2)}")
  }

  def apply(filename: String): Graph = new Graph(filename)
}


g.txt

7 7
0 1
0 2
1 3
1 4
2 3
2 6
5 6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值