Go语言实现拓扑排序-1

写在前面

所谓算法,一定一定是要落地才有意义的,任何一个在计算机领域流行的算法,一定有与之深度match的业务场景。这里之所以总结拓扑排序,是因为拓扑排序的应用场景还是非常丰富的。

拓扑排序应用场景

从经典的(人人都刷过)的课程表排课问题,到任何一些存在前驱和后驱关系的元素排序问题,其实都是典型的拓扑排序问题。如果细化问题,拓扑排序更多时候是有向图遍历或者排序。

Go语言实现拓扑排序

业务需求

n门课程,其各个课程之间的有的课程需要先修,对应关系以map给出,例如:

“信号与系统”:{
     "通信原理",“线性代数”,“高等数学”}
“通信原理”:{
     “高等数学”,“线性代数”}
“线性代数”:{
     "高等数学"}

这里还需要判断的一点是,如果其先修后修关系出现矛盾,则无法排课表,这一点也需要判断。

基本思路

这里给的基本思路是从DFS下手的:利用迭代递归实现对有向图的DFS。只不过这里需要判断有向图是否有环,如果有环就无法排出可以使用的课表。有无环的判断可以使用一个标志常量来描述如下:

const (
		NOTVISIT = iota
		VISITING
		VISITED
	)

NOTVISIT表示有向图中的节点还未被DFS遍历,VISITING表示该节点已经进入递归遍历过程中,但是还未被加入到最后的遍历结果切片中,而VISITED表示该节点已经递归完成,被加入到了最后遍历结果的切片中。如此一分析,有向图是否有环的判断就一目了然,在某一次递归中,如果发现有某个VISITING状态的节点出现了两次,一定存在环。

基本代码

package main

import (
	"fmt"
)

func main() {
     
	numsTjq := [][]int{
     {
     1,0},{
     2,0},{
     3,1},{
     3,2}}
	for _,num := range findOrder(4,numsTjq) {
     
		fmt.Println(num)
	}
}

func findOrder(numCrouse int, prerequisites [][]int) []int {
     
	const (
		NOTVISIT = iota
		VISITING
		VISITED
	)
	hasRing := false
	dfsMap := make(map[int][]int)
	hasMap := make(map[int]bool)
	for i:=0; i<len(prerequisites); i++ {
     
		dfsMap[prerequisites[i][0]] = append(dfsMap[prerequisites[i][0]],prerequisites[i][1])
		hasMap[prerequisites[i][0]] = true
		hasMap[prerequisites[i][1]] = true
		//fmt.Printf("key is %d, value is %d",prerequisites[i][0], prerequisites[i][1])
	}
	visited := make(map[int]int) //标记某元素是否使用过 在有向图无环的时候需要配置三个量:未访问、访问中,已访问
	var searchDfs func(nums []int)
	var order []int
	searchDfs = func(nums []int){
     
		for _, num := range nums {
     
			if hasRing {
     
				return
			}else {
     
				if visited[num] == NOTVISIT{
     
					visited[num] = VISITING
					searchDfs(dfsMap[num])
					order = append(order, num)
					visited[num] = VISITED
				}else if visited[num] == VISITING {
     
					hasRing = true
					return
				}
			}
		}
	}
	var keys []int
	//注意返回值
	for key := range dfsMap {
     
		//fmt.Println(key)
		keys = append(keys, key)
	}
	searchDfs(keys)
	if hasRing {
     
		res := []int{
     }
		return res
	}
	if len(order) < numCrouse {
     
		res := []int{
     }
		for i := 0; i<numCrouse; i++ {
     
			if ! hasMap[i]  {
     
				res = append(res, i)
			}
		}
		res = append(res,order...)
		return res
	}
	return order
}

此处代码存在一些数据处理的过程,各位无须在意,只需借鉴基本思路即可。

你可能感兴趣的:(go,算法,数据库,算法,dfs,数据结构)