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()
}
}
结果展示:

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

被折叠的 条评论
为什么被折叠?



