scala实现图结构及遍历算法(一)

本文使用Scala实现图数据结构,包括构造图的边、图对象接口和抽象类,以及实现广度优先和深度优先遍历算法。通过具体代码示例展示了如何创建和操作图结构。

scala实现图结构及简单遍历算法(一)

本文使用scala2.12版本实现数据结构中的图结构,并实现一些简单算法,后续还有更新。

代码实现

构造图的 边class

import scala.collection.mutable
import scala.collection.mutable.ListBuffer

class Edge {
  var v1: Int = _
  var v2: Int = _

  /**
    * 副构造器
    */
  def this(v1: Int, v2: Int) {
    this //调用主构造器
    this.v1 = v1
    this.v2 = v2
  }

  override def toString: String = s"Edge($v1,$v2)"
}

构造图对象主接口

trait Graph[T] {
  def getSize: Int //返回图中顶点数
  def getVertices: ListBuffer[T] //返回图的顶点集合
  def getVertex(index: Int): T //返回指定下标的顶点
  def getIndex(t: T): Int //返回指定顶点的下标v
  def getNeighbors(index: Int): ListBuffer[Int] //返回制定下标顶点的邻居
  def getDegree(v: Int): Int //返回制定下标顶点的度
  def printEdges: Unit //打印边
  def clear(): Unit //清楚图
  def addVertex(vertex: T): Boolean //如果v添加到图中,返回true;如果v已经在图中,返回false
  /*
  *添加从u到v的边到图中,如果u或者v是无效的,则抛出异常,
  *边添加成功则返回true,如果(u,v)已经在图中则返回false
  */
  def addEdge(in: Int, v2: Int): Boolean

  def addEdge(e: Edge): Boolean
}

构造图抽象类

class AbstractGraph[T] extends Graph[T] {
  var vertices: ListBuffer[T] = new ListBuffer[T]()
  var neighbors: ListBuffer[ListBuffer[Edge]] = new ListBuffer[ListBuffer[Edge]]()

  def this(vertices: Array[T], edges: Array[Array[Int]]) {
    this()
    vertices.foreach(v => addVertex(v))
    createAdjacencyLists(edges, vertices.length)
  }

  def this(vertices: Seq[T], edges: Seq[Edge]) {
    this()
    vertices.foreach(i => addVertex(i))
    createAdjacencyLists(edges, vertices.length)
  }

  /**
    * 创建邻接表
    */
  def createAdjacencyLists(edges: Array[Array[Int]], numberOfVertices: Int): Unit = {
    edges.foreach(edge => addEdge(edge(0), edge(1)))
  }

  /**
    * 创建邻接表
    */
  def createAdjacencyLists(edges: Seq[Edge], numberOfVertices: Int): Unit = {
    edges.foreach(edge => addEdge(edge.v1, edge.v2))
  }

  override def getSize: Int = vertices.size

  override def getVertices: ListBuffer[T] = vertices

  override def getVertex(index: Int): T = vertices(index)

  override def getIndex(t: T): Int = vertices.indexOf(t)

  override def getNeighbors(index: Int): ListBuffer[Int] = {
    val result = new ListBuffer[Int]()
    neighbors(index).foreach(e => result.append(e.v2))
    result
  }

  override def getDegree(v: Int): Int = neighbors(v).size

  override def printEdges: Unit = {
    neighbors.indices.foreach(u => {
      println(s"${getVertex(u)}($u):")
      neighbors(u).foreach(e => println(s"(${getVertex(e.v1)},${getVertex(e.v2)})"))
    })
  }
  override def clear(): Unit = {
    vertices.clear()
    neighbors.clear()
  }
  override def addVertex(vertex: T): Boolean = {
    if (vertices.contains(vertex)) false
    else {
      vertices.append(vertex)
      neighbors.append(new ListBuffer[Edge]())
      true
    }
  }
  override def addEdge(e: Edge): Boolean = {
    if (e.v1 < 0 || e.v1 > getSize - 1) throw new IllegalArgumentException("No such index:" + e.v1)
    if (e.v2 < 0 || e.v2 > getSize - 1) throw new IllegalArgumentException("No such index:" + e.v2)
    if (!neighbors(e.v1).contains(e)) {
      neighbors(e.v1).append(e)
      true
    } else false
  }

  override def addEdge(v1: Int, v2: Int): Boolean = addEdge(new Edge(v1, v2))

  /**
    * 广度优先遍历算法
    */
  def dfs(u: Int, parent: Array[Int], searchOrder: ListBuffer[Int], isVisited: Array[Boolean]): Unit = {
    searchOrder.append(u)
    isVisited(u) = true
    neighbors(u).foreach(e => {
      if (!isVisited(e.v2)) {
        parent(e.v2) = u
        dfs(e.v2, parent, searchOrder, isVisited)
      }
    })
  }

  /**
    * 深度优先遍历算法
    */
  def dfs(v: Int): Tree = {
    val searchOrder = new ListBuffer[Int]
    val verSize = vertices.size
    val parent = new Array[Int](verSize)
    val parentRange = parent.indices
    parentRange.foreach(f => parent(f) = -1)
    val isVisited: Array[Boolean] = new Array[Boolean](verSize)
    dfs(v, parent, searchOrder, isVisited)
    new Tree(v, parent, searchOrder)
  }

  /**
    * 广度优先遍历算法
    */
  def bfs(v: Int): Tree = {
    val searchOrder = new ListBuffer[Int]()
    val verSize = vertices.size
    val parent = new Array[Int](verSize)
    parent.indices.foreach(f => parent(f) = -1)
    val queue: mutable.Queue[Int] = mutable.Queue[Int]()
    val isVisited = new Array[Boolean](verSize)
    queue.enqueue(v)
    isVisited(v) = true
    while (queue.nonEmpty) {
      val u = queue.dequeue()
      searchOrder.append(u)
      neighbors(u).foreach(e => {
        if (!isVisited(e.v2)) {
          queue.enqueue(e.v2)
          parent(e.v2) = e.v1
          isVisited(e.v2) = true
        }
      })
    }
    new Tree(v, parent, searchOrder)
  }

  /**
    * 树结构类型 -- 内部类
    */
  class Tree {
    var root: Int = _
    var parent: Array[Int] = _
    var searchOrder: ListBuffer[Int] = _
    def this(root: Int, parent: Array[Int], searchOrder: ListBuffer[Int]) {
      this
      this.root = root
      this.parent = parent
      this.searchOrder = searchOrder
    }

    def getNumberOfVerticesFound: Int = searchOrder.size

    def getPath(index: Int): ListBuffer[T] = {
      val path: ListBuffer[T] = new ListBuffer[T]
      var ind = index
      while (ind != -1) {
        path.append(vertices(index))
        ind = parent(ind)
      }
      path
    }

    def printPath(index: Int): Unit = {
      val path = getPath(index)
      println(s"A path from ${vertices(root)} to ${vertices(index)}:")
      path.indices.reverse.foreach(i => print(path(i) + " "))
    }

    def printTree(): Unit = {
      println(s"Root is:  ${vertices(root)}")
      print(s"Edges: ")
      parent.indices.foreach(i => if (parent(i) != -1) print(s"(${vertices(parent(i))},${vertices(i)}) "))
      println
    }
  }

}

测试对象

object TestGraph {
  def main(args: Array[String]): Unit = {
    val arr = Array("腾讯", "阿里巴巴", "蚂蚁金服", "支付宝", "花呗", "王者荣耀", "今日头条")
    val edgeList = new ListBuffer[Edge]()
    edgeList.append(new Edge(0, 5))
    edgeList.append(new Edge(1, 2))
    edgeList.append(new Edge(2, 3))
    edgeList.append(new Edge(3, 4))
    val myGraph: AbstractGraph[String] = new AbstractGraph[String](arr.toSeq, edgeList)
    myGraph.neighbors.foreach(println)
    myGraph.bfs(1).printTree()
  }
}

结果展示:
在这里插入图片描述
未完待续……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值