diff --git a/codes/kotlin/chapter_graph/graph_adjacency_list.kt b/codes/kotlin/chapter_graph/graph_adjacency_list.kt new file mode 100644 index 000000000..3ffe9af25 --- /dev/null +++ b/codes/kotlin/chapter_graph/graph_adjacency_list.kt @@ -0,0 +1,121 @@ +/** + * File: graph_adjacency_list.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_graph + +import utils.Vertex + +/* 基于邻接表实现的无向图类 */ +class GraphAdjList(edges: Array>) { + // 邻接表,key:顶点,value:该顶点的所有邻接顶点 + val adjList: MutableMap> = HashMap() + + /* 构造函数 */ + init { + // 添加所有顶点和边 + for (edge in edges) { + addVertex(edge[0]!!); + addVertex(edge[1]!!); + addEdge(edge[0]!!, edge[1]!!); + } + } + + /* 获取顶点数量 */ + fun size(): Int { + return adjList.size + } + + /* 添加边 */ + fun addEdge(vet1: Vertex, vet2: Vertex) { + if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2) + throw IllegalArgumentException() + // 添加边 vet1 - vet2 + adjList[vet1]?.add(vet2) + adjList[vet2]?.add(vet1); + } + + /* 删除边 */ + fun removeEdge(vet1: Vertex, vet2: Vertex) { + if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2) + throw IllegalArgumentException() + // 删除边 vet1 - vet2 + adjList[vet1]?.remove(vet2); + adjList[vet2]?.remove(vet1); + } + + /* 添加顶点 */ + fun addVertex(vet: Vertex) { + if (adjList.containsKey(vet)) + return + // 在邻接表中添加一个新链表 + adjList[vet] = mutableListOf() + } + + /* 删除顶点 */ + fun removeVertex(vet: Vertex) { + if (!adjList.containsKey(vet)) + throw IllegalArgumentException() + // 在邻接表中删除顶点 vet 对应的链表 + adjList.remove(vet); + // 遍历其他顶点的链表,删除所有包含 vet 的边 + for (list in adjList.values) { + list.remove(vet) + } + } + + /* 打印邻接表 */ + fun print() { + println("邻接表 =") + for (pair in adjList.entries) { + val tmp = ArrayList() + for (vertex in pair.value) { + tmp.add(vertex.value) + } + println("${pair.key.value}: $tmp,") + } + } +} + +/* Driver Code */ +fun main() { + /* 初始化无向图 */ + val v: Array = Vertex.valsToVets(intArrayOf(1, 3, 2, 5, 4)) + val edges = arrayOf( + arrayOf(v[0], v[1]), + arrayOf(v[0], v[3]), + arrayOf(v[1], v[2]), + arrayOf(v[2], v[3]), + arrayOf(v[2], v[4]), + arrayOf(v[3], v[4]) + ) + val graph = GraphAdjList(edges) + println("\n初始化后,图为") + graph.print() + + /* 添加边 */ + // 顶点 1, 2 即 v[0], v[2] + graph.addEdge(v[0]!!, v[2]!!) + println("\n添加边 1-2 后,图为") + graph.print() + + /* 删除边 */ + // 顶点 1, 3 即 v[0], v[1] + graph.removeEdge(v[0]!!, v[1]!!) + println("\n删除边 1-3 后,图为") + graph.print() + + /* 添加顶点 */ + val v5 = Vertex(6) + graph.addVertex(v5) + println("\n添加顶点 6 后,图为") + graph.print() + + /* 删除顶点 */ + // 顶点 3 即 v[1] + graph.removeVertex(v[1]!!) + println("\n删除顶点 3 后,图为") + graph.print() +} \ No newline at end of file diff --git a/codes/kotlin/chapter_graph/graph_adjacency_matrix.kt b/codes/kotlin/chapter_graph/graph_adjacency_matrix.kt new file mode 100644 index 000000000..eb1ffb358 --- /dev/null +++ b/codes/kotlin/chapter_graph/graph_adjacency_matrix.kt @@ -0,0 +1,131 @@ +/** + * File: graph_adjacency_matrix.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_graph + +import utils.printMatrix + +/* 基于邻接矩阵实现的无向图类 */ +class GraphAdjMat(vertices: IntArray, edges: Array) { + val vertices: MutableList = ArrayList() // 顶点列表,元素代表“顶点值”,索引代表“顶点索引” + val adjMat: MutableList> = ArrayList() // 邻接矩阵,行列索引对应“顶点索引” + + /* 构造函数 */ + init { + // 添加顶点 + for (vertex in vertices) { + addVertex(vertex) + } + // 添加边 + // 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引 + for (edge in edges) { + addEdge(edge[0], edge[1]) + } + } + + /* 获取顶点数量 */ + fun size(): Int { + return vertices.size + } + + /* 添加顶点 */ + fun addVertex(value: Int) { + val n = size() + // 向顶点列表中添加新顶点的值 + vertices.add(value) + // 在邻接矩阵中添加一行 + val newRow: MutableList = mutableListOf() + for (j in 0..= size()) throw IndexOutOfBoundsException() + // 在顶点列表中移除索引 index 的顶点 + vertices.removeAt(index) + // 在邻接矩阵中删除索引 index 的行 + adjMat.removeAt(index) + // 在邻接矩阵中删除索引 index 的列 + for (row in adjMat) { + row.removeAt(index) + } + } + + /* 添加边 */ + // 参数 i, j 对应 vertices 元素索引 + fun addEdge(i: Int, j: Int) { + // 索引越界与相等处理 + if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException() + // 在无向图中,邻接矩阵关于主对角线对称,即满足 (i, j) == (j, i) + adjMat[i][j] = 1; + adjMat[j][i] = 1; + } + + /* 删除边 */ + // 参数 i, j 对应 vertices 元素索引 + fun removeEdge(i: Int, j: Int) { + // 索引越界与相等处理 + if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) throw java.lang.IndexOutOfBoundsException() + adjMat[i][j] = 0; + adjMat[j][i] = 0; + } + + /* 打印邻接矩阵 */ + fun print() { + print("顶点列表 = ") + println(vertices); + println("邻接矩阵 ="); + printMatrix(adjMat) + } +} + +/* Driver Code */ +fun main() { + /* 初始化无向图 */ + // 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引 + val vertices = intArrayOf(1, 3, 2, 5, 4) + val edges = arrayOf( + intArrayOf(0, 1), + intArrayOf(0, 3), + intArrayOf(1, 2), + intArrayOf(2, 3), + intArrayOf(2, 4), + intArrayOf(3, 4) + ) + val graph = GraphAdjMat(vertices, edges) + println("\n初始化后,图为") + graph.print() + + /* 添加边 */ + // 顶点 1, 2 的索引分别为 0, 2 + graph.addEdge(0, 2) + println("\n添加边 1-2 后,图为") + graph.print() + + /* 删除边 */ + // 顶点 1, 3 的索引分别为 0, 1 + graph.removeEdge(0, 1) + println("\n删除边 1-3 后,图为") + graph.print() + + /* 添加顶点 */ + graph.addVertex(6) + println("\n添加顶点 6 后,图为") + graph.print() + + /* 删除顶点 */ + // 顶点 3 的索引为 1 + graph.removeVertex(1) + println("\n删除顶点 3 后,图为") + graph.print() +} \ No newline at end of file diff --git a/codes/kotlin/chapter_graph/graph_bfs.kt b/codes/kotlin/chapter_graph/graph_bfs.kt new file mode 100644 index 000000000..05026602b --- /dev/null +++ b/codes/kotlin/chapter_graph/graph_bfs.kt @@ -0,0 +1,65 @@ +/** + * File: graph_bfs.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_graph + +import utils.Vertex +import java.util.* + +/* 广度优先遍历 */ +// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点 +fun graphBFS(graph: GraphAdjList, startVet: Vertex): List { + // 顶点遍历序列 + val res: MutableList = ArrayList() + // 哈希表,用于记录已被访问过的顶点 + val visited: MutableSet = HashSet() + visited.add(startVet) + // 队列用于实现 BFS + val que: Queue = LinkedList() + que.offer(startVet) + // 以顶点 vet 为起点,循环直至访问完所有顶点 + while (!que.isEmpty()) { + val vet = que.poll() // 队首顶点出队 + res.add(vet) // 记录访问顶点 + // 遍历该顶点的所有邻接顶点 + for (adjVet in graph.adjList[vet]!!) { + if (visited.contains(adjVet)) continue // 跳过已被访问的顶点 + + que.offer(adjVet) // 只入队未访问的顶点 + visited.add(adjVet) // 标记该顶点已被访问 + } + } + // 返回顶点遍历序列 + return res +} + +/* Driver Code */ +fun main() { + /* 初始化无向图 */ + val v = Vertex.valsToVets(intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)) + val edges = arrayOf( + arrayOf(v[0], v[1]), + arrayOf(v[0], v[3]), + arrayOf(v[1], v[2]), + arrayOf(v[1], v[4]), + arrayOf(v[2], v[5]), + arrayOf(v[3], v[4]), + arrayOf(v[3], v[6]), + arrayOf(v[4], v[5]), + arrayOf(v[4], v[7]), + arrayOf(v[5], v[8]), + arrayOf(v[6], v[7]), + arrayOf(v[7], v[8]) + ) + val graph = GraphAdjList(edges) + println("\n初始化后,图为") + graph.print() + + /* 广度优先遍历 */ + val res = graphBFS(graph, v[0]!!) + println("\n广度优先遍历(BFS)顶点序列为") + println(Vertex.vetsToVals(res)) +} \ No newline at end of file diff --git a/codes/kotlin/chapter_graph/graph_dfs.kt b/codes/kotlin/chapter_graph/graph_dfs.kt new file mode 100644 index 000000000..c7c99a1ab --- /dev/null +++ b/codes/kotlin/chapter_graph/graph_dfs.kt @@ -0,0 +1,62 @@ +/** + * File: graph_dfs.kt + * Created Time: 2024-01-25 + * Author: curtishd (1023632660@qq.com) + */ + +package chapter_graph + +import utils.Vertex + +/* 深度优先遍历辅助函数 */ +fun dfs( + graph: GraphAdjList, + visited: MutableSet, + res: MutableList, + vet: Vertex? +) { + res.add(vet) // 记录访问顶点 + visited.add(vet) // 标记该顶点已被访问 + // 遍历该顶点的所有邻接顶点 + for (adjVet in graph.adjList[vet]!!) { + if (visited.contains(adjVet)) continue // 跳过已被访问的顶点 + // 递归访问邻接顶点 + dfs(graph, visited, res, adjVet) + } +} + +/* 深度优先遍历 */ +// 使用邻接表来表示图,以便获取指定顶点的所有邻接顶点 +fun graphDFS( + graph: GraphAdjList, + startVet: Vertex? +): List { + // 顶点遍历序列 + val res: MutableList = ArrayList() + // 哈希表,用于记录已被访问过的顶点 + val visited: MutableSet = HashSet() + dfs(graph, visited, res, startVet) + return res +} + +/* Driver Code */ +fun main() { + /* 初始化无向图 */ + val v = Vertex.valsToVets(intArrayOf(0, 1, 2, 3, 4, 5, 6)) + val edges = arrayOf( + arrayOf(v[0], v[1]), + arrayOf(v[0], v[3]), + arrayOf(v[1], v[2]), + arrayOf(v[2], v[5]), + arrayOf(v[4], v[5]), + arrayOf(v[5], v[6]) + ) + val graph = GraphAdjList(edges) + println("\n初始化后,图为") + graph.print() + + /* 深度优先遍历 */ + val res = graphDFS(graph, v[0]) + println("\n深度优先遍历(DFS)顶点序列为") + println(Vertex.vetsToVals(res)) +} \ No newline at end of file