Mind and Hand Help

Graph Definition

通用接口

interface Graph { fun isEmpty(): Boolean { return getVertexesNum() == 0 } fun isDirected(): Boolean fun isWeighted(): Boolean fun getVertexesNum(): Int = vertexIndex().size() fun getEdgeNum(): Int fun getVertexes(): List<Vertex> = vertexIndex().getVertexes() fun getEdges(): List<Edge> fun getEdge(from: String, to: String): Edge? { val fromV = vertexIndex().getVertex(from) val toV = vertexIndex().getVertex(to) if (fromV == null || toV == null) { return null } return getEdge(fromV.id, toV.id) } fun getEdge(from: Int, to: Int): Edge? fun connect(from: String, to: String) = connect(from, to, DEFAULT_UNWEIGHTED_VALUE) fun connect(from: String, to: String, weight: Double) fun adjacentEdges(name: String): List<Edge> { return vertexIndex().getVertex(name)?.let { vertex -> adjacentEdges(vertex.id) } ?: emptyList() } fun adjacentEdges(id: Int): List<Edge> fun clear() fun showGraph() fun vertexIndex(): VertexIndex // 获取邻接矩阵 fun getAdjacencyMatrix(): Array<Array<Double?>>? = null // 获取邻接表 fun getAdjacencyList(): Array<TreeMap<Int, Double>>? = null }

图的实现

稀疏图主要用邻接表实现,稠密图主要用邻接矩阵实现

稀疏图

class SparseGraph : Graph { companion object { val log = getLogger(DenseGraph::class.java) } private val directed: Boolean private val weighted: Boolean private val vertexIndex = VertexIndex() private var adjacencyList: Array<TreeMap<Int, Double>> = Array(0) { TreeMap() } private var edgesCount: Int = 0 constructor(directed: Boolean, weighted: Boolean) { this.directed = directed this.weighted = weighted } override fun isDirected(): Boolean = this.directed override fun isWeighted(): Boolean = this.weighted override fun getEdgeNum(): Int = this.edgesCount override fun getEdges(): List<Edge> { return adjacencyList.flatMapIndexed { from, edges -> if (edges.isEmpty()) { emptyList() // 返回空列表而不是 null } else { val fromV = vertexIndex.getVertex(from)!! edges.map { (toId, weight) -> val toV = vertexIndex.getVertex(toId)!! Edge(from = fromV, to = toV, weight = weight) } } } } override fun getEdge(from: Int, to: Int): Edge? { if (from < 0 || to < 0 || from >= vertexIndex.size() || to >= vertexIndex.size()) { return null } if (from == to) { return null } return adjacencyList[from].let { it[to]?.let { weight -> val fromVertex = vertexIndex.getVertex(from)!! val toVertex = vertexIndex.getVertex(to)!! Edge(from = fromVertex, to = toVertex, weight = weight) } } } override fun connect(from: String, to: String, weight: Double) { if (from.isBlank() || to.isBlank()) { throw IllegalArgumentException("Vertex names cannot be empty") } if (from == to) { return } this.connect( vertexIndex.createVertex(from).id, vertexIndex.createVertex(to).id, weight, this.directed ) } private fun connect(from: Int, to: Int, weight: Double, directed: Boolean) { this.expand(maxOf(from, to) + 1) val edges = adjacencyList[from] val isNewEdge = !edges.containsKey(to) if (!isNewEdge) { log.warn("Edge from $from to $to already exists, updating weight to $weight") this.edgesCount-- } edges[to] = weight this.edgesCount++ if (!directed) { this.connect(to, from, weight, true) } } private fun expand(size: Int) { if (size > adjacencyList.size) { val newAdjList = Array(size) { TreeMap<Int, Double>() } System.arraycopy(adjacencyList, 0, newAdjList, 0, adjacencyList.size) this.adjacencyList = newAdjList } } override fun adjacentEdges(id: Int): List<Edge> { if (id < 0 || id >= vertexIndex.size()) { return emptyList() } val fromVertex = vertexIndex.getVertex(id)!! val neighbors = adjacencyList[id] return neighbors.map { (toId, weight) -> val toVertex = vertexIndex.getVertex(toId) ?: return@map null Edge(from = fromVertex, to = toVertex, weight = weight) }.filterNotNull() } override fun clear() { vertexIndex.clear() adjacencyList = Array(0) { TreeMap() } edgesCount = 0 } override fun showGraph() { println("Graph: ${if (directed) "Directed" else "Undirected"}, ${if (weighted) "Weighted" else "Unweighted"}") println("Vertices: ${vertexIndex.size()}") println("Edges: $edgesCount") // 打印邻接表 println("\nAdjacency List:") val startFmt = "%s(%d) : " val toFmt = "%s(%d) -- %.2f -> %s(%d) " adjacencyList.forEachIndexed { from, map -> if (map.isEmpty()) { return@forEachIndexed } val fromV = vertexIndex.getVertex(from)!! print(startFmt.format(fromV.name, fromV.id)) map.forEach { (toId, weight) -> val toV = vertexIndex.getVertex(toId)!! print(toFmt.format(fromV.name, fromV.id, weight, toV.name, toId)) } println() } } override fun vertexIndex(): VertexIndex = this.vertexIndex override fun getAdjacencyList(): Array<TreeMap<Int, Double>> = this.adjacencyList }

稠密图

class DenseGraph : Graph { companion object { val log = getLogger(DenseGraph::class.java) } private val directed: Boolean private val weighted: Boolean private var adjacencyMatrix: Array<Array<Double?>> private val vertexIndex = VertexIndex() private var edgesCount: Int = 0 constructor(directed: Boolean, weighted: Boolean) { this.directed = directed this.weighted = weighted adjacencyMatrix = Array(2) { Array(2) { null } } } override fun isDirected(): Boolean = this.directed override fun isWeighted(): Boolean = this.weighted override fun getEdgeNum(): Int = this.edgesCount override fun getEdges(): List<Edge> { return if (isEmpty()) { emptyList() } else { val edges = mutableListOf<Edge>() for (i in 0 until adjacencyMatrix.size) { for (j in 0 until adjacencyMatrix.size) { adjacencyMatrix[i][j]?.let { weight -> val fromV = vertexIndex.getVertex(i)!! val toV = vertexIndex.getVertex(j)!! edges.add(Edge(from = fromV, to = toV, weight = weight)) } } } edges } } override fun getEdge(from: Int, to: Int): Edge? { if (from < 0 || to < 0 || from >= vertexIndex.size() || to >= vertexIndex.size()) { return null } if (from == to) { return null // No self-loops in this implementation } val weight = adjacencyMatrix[from][to] return if (weight == null) { null } else { Edge( from = vertexIndex.getVertex(from)!!, to = vertexIndex.getVertex(to)!!, weight = weight ) } } override fun connect(from: String, to: String, weight: Double) { if (from.isBlank() || to.isBlank()) { throw IllegalArgumentException("Vertex names cannot be empty") } if (from == to) { return } val fromV = vertexIndex.createVertex(from) val toV = vertexIndex.createVertex(to) this.expand(vertexIndex.size()) this.connect(fromV.id, toV.id, weight, directed = this.directed) } private fun expand(size: Int) { if (size > adjacencyMatrix.size) { val newSize = size val newMatrix = Array(newSize) { Array<Double?>(newSize) { null } } adjacencyMatrix.forEachIndexed { i, row -> System.arraycopy(row, 0, newMatrix[i], 0, row.size) } adjacencyMatrix = newMatrix } } private fun connect(from: Int, to: Int, weight: Double, directed: Boolean) { adjacencyMatrix[from][to]?.let { existingWeight -> log.debug("Edge from $from to $to already exists with weight $existingWeight, updating to $weight") edgesCount-- } adjacencyMatrix[from][to] = weight edgesCount++ if (!directed) { this.connect(to, from, weight, true) } } override fun adjacentEdges(id: Int): List<Edge> { if (isEmpty() || id < 0 || id >= vertexIndex.size()) { return emptyList() } val fromV = vertexIndex.getVertex(id)!! return adjacencyMatrix[id].mapIndexedNotNull { toIndex, weight -> weight?.let { val toV = vertexIndex.getVertex(toIndex)!! Edge(from = fromV, to = toV, weight = it) } } } override fun clear() { vertexIndex.clear() edgesCount = 0 adjacencyMatrix = Array(2) { Array(2) { null } } } override fun showGraph() { println("Graph: ${if (directed) "Directed" else "Undirected"}, ${if (weighted) "Weighted" else "Unweighted"}") println("Vertices: ${vertexIndex.size()}") println("Edges: $edgesCount") // // 先打印顶点信息 println("Vertex Information:") vertexIndex.getVertexes().forEach(::println) // 打印 matrix 并在第一行和第一列显示顶点信息 println("\nAdjacency Matrix:") // 打印顶点ID作为列标题 print(" ") // 留出行标题的空间 for (i in 0 until vertexIndex.size()) { val v = vertexIndex.getVertex(i)!! print(beautify("${v.id}:${v.name}", 5)) } println() // 打印矩阵内容 for (i in 0 until vertexIndex.size()) { val v = vertexIndex.getVertex(i)!! print(beautify("${v.id}:${v.name}", 5)) for (j in 0 until vertexIndex.size()) { val element = adjacencyMatrix[i][j] if (element != null) { print(beautify(element.toString(), 5)) } else { print(beautify("nil", 5)) } } println() } } override fun vertexIndex(): VertexIndex = this.vertexIndex override fun getAdjacencyMatrix(): Array<Array<Double?>>? = this.adjacencyMatrix }
27 January 2026