美文网首页
拓扑排序

拓扑排序

作者: 云飞扬1 | 来源:发表于2020-12-07 13:52 被阅读0次

什么是拓扑排序呢, 具体可参考网上别人的总结https://www.jianshu.com/p/b59db381561a,我这里不赘述了。之所以想研究这个算法呢?记得以前学 java 的时候,很多工程的构建是基于 Ant 来构建的,后来又通过 maven 来构建,再后来学习 Android 的时候,Android 工程是通过 Gradle 来构建的,Gradle 构建过程中会有很多独立的 task 执行,这些 task 又有依赖关系,有的 task 必须在某个 task 执行之前执行,还有就是模块的依赖关系,当时就在想编译系统是怎么确定这些前后依赖顺序的,后来了解到拓扑排序算之后才恍然大悟,这不就是一个典型的拓扑排序实践案例么。
拓扑排序主要有2种实现方式,下面用 Kotlin 代码分别实现:

1. 拓扑排序-Kahn算法

class TopoGraph(val size: Int) {

    //图的临界矩阵定义好
    private val adj: Array<LinkedList<Int>> = Array(size) {
        LinkedList<Int>()
    }

    //定义图的边
    fun addEdge(s: Int, t: Int) {
        adj[s].add(t)
    }

    /**
     * 拓扑排序 - Kahn算法
     */
    fun topoSortByKahn() {
        var inDegreeArr = IntArray(size)
        //计算所有顶点的入度 inDegree
        for (i in adj.indices) {
            var list = adj[i]
            for (item in list) {
                inDegreeArr[item]++
            }
        }
        //保存所有入度为 0 的顶点
        val queue = LinkedList<Int>()
        //先找出所有 inDegree = 0 的顶点
        for (i in inDegreeArr.indices) {
            if (inDegreeArr[i] == 0) {
                queue.add((i))
            }
        }
        while (queue.isNotEmpty()) {
            //inDegree = 0 的顶点先出队列
            var i = queue.remove()
            print("-> ${i} ")
            for (item in adj[i]) {
                //所有该顶点能到的其他顶点的 inDegree - 1
                inDegreeArr[item]--
                if (inDegreeArr[item] == 0) {
                    //如果 inDegree = 0 则先入队,然后循环处理
                    queue.add(item)
                }
            }
        }       
    }
}

2. 拓扑排序-DFS算法

    /**
     * 拓扑排序 - DFS算法(深度优先遍历)
     */
    fun topoSortByDfs() {
        //逆邻接表
        var reverseAdjList = Array(size) {
            LinkedList<Int>()
        }
        //记录节点是否已经遍历
        var visited = BooleanArray(size) { false }
        for (i in adj.indices) {
            var list = adj[i]
            for (item in list) {
                reverseAdjList[item].add(i)
            }
        }
        for (i in 0 until size) {
            if (!visited[i])
                dfs(reverseAdjList, visited, i)
        }
    }

    //类似二叉树的后序遍历
    private fun dfs(reverseAdjList: Array<LinkedList<Int>>, visited: BooleanArray, vertex: Int) {
        if (vertex >= size || visited[vertex]) {
            return
        }
        visited[vertex] = true
        var list = reverseAdjList[vertex]
        for (v in list) {
            if (!visited[v])
                dfs(reverseAdjList, visited, v)
        }
        print("-> ${vertex} ")
    }

相关文章

网友评论

      本文标题:拓扑排序

      本文链接:https://www.haomeiwen.com/subject/cxttgktx.html