github.com/lianghucheng/zrddz@v0.0.0-20200923083010-c71f680932e2/src/gopkg.in/mgo.v2/txn/tarjan.go (about) 1 package txn 2 3 import ( 4 "gopkg.in/mgo.v2/bson" 5 "sort" 6 ) 7 8 func tarjanSort(successors map[bson.ObjectId][]bson.ObjectId) [][]bson.ObjectId { 9 // http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm 10 data := &tarjanData{ 11 successors: successors, 12 nodes: make([]tarjanNode, 0, len(successors)), 13 index: make(map[bson.ObjectId]int, len(successors)), 14 } 15 16 for id := range successors { 17 id := bson.ObjectId(string(id)) 18 if _, seen := data.index[id]; !seen { 19 data.strongConnect(id) 20 } 21 } 22 23 // Sort connected components to stabilize the algorithm. 24 for _, ids := range data.output { 25 if len(ids) > 1 { 26 sort.Sort(idList(ids)) 27 } 28 } 29 return data.output 30 } 31 32 type tarjanData struct { 33 successors map[bson.ObjectId][]bson.ObjectId 34 output [][]bson.ObjectId 35 36 nodes []tarjanNode 37 stack []bson.ObjectId 38 index map[bson.ObjectId]int 39 } 40 41 type tarjanNode struct { 42 lowlink int 43 stacked bool 44 } 45 46 type idList []bson.ObjectId 47 48 func (l idList) Len() int { return len(l) } 49 func (l idList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 50 func (l idList) Less(i, j int) bool { return l[i] < l[j] } 51 52 func (data *tarjanData) strongConnect(id bson.ObjectId) *tarjanNode { 53 index := len(data.nodes) 54 data.index[id] = index 55 data.stack = append(data.stack, id) 56 data.nodes = append(data.nodes, tarjanNode{index, true}) 57 node := &data.nodes[index] 58 59 for _, succid := range data.successors[id] { 60 succindex, seen := data.index[succid] 61 if !seen { 62 succnode := data.strongConnect(succid) 63 if succnode.lowlink < node.lowlink { 64 node.lowlink = succnode.lowlink 65 } 66 } else if data.nodes[succindex].stacked { 67 // Part of the current strongly-connected component. 68 if succindex < node.lowlink { 69 node.lowlink = succindex 70 } 71 } 72 } 73 74 if node.lowlink == index { 75 // Root node; pop stack and output new 76 // strongly-connected component. 77 var scc []bson.ObjectId 78 i := len(data.stack) - 1 79 for { 80 stackid := data.stack[i] 81 stackindex := data.index[stackid] 82 data.nodes[stackindex].stacked = false 83 scc = append(scc, stackid) 84 if stackindex == index { 85 break 86 } 87 i-- 88 } 89 data.stack = data.stack[:i] 90 data.output = append(data.output, scc) 91 } 92 93 return node 94 }