github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/algorithm/datastructures/topology/topo.go (about)

     1  package topology
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/qiuhoude/go-web/algorithm/datastructures/queue"
     6  	"github.com/qiuhoude/go-web/algorithm/datastructures/stack"
     7  )
     8  
     9  /*
    10  
    11  拓扑排序中
    12  1. kahn算法
    13  2. DFS算法
    14  
    15  比如 依赖关系 (箭头表示 xx 依赖 xxx ) A->B , B->C ,C->D
    16  求出依赖关系
    17  使用 有向图 的数据结构进行处理
    18  
    19  */
    20  
    21  // 顶点
    22  type vertex struct {
    23  	id int
    24  	v  interface{}
    25  }
    26  
    27  func (v *vertex) String() string {
    28  	return fmt.Sprintf("(%v, %v)", v.id, v.v)
    29  }
    30  
    31  func newVertex(id int, v interface{}) *vertex {
    32  	return &vertex{
    33  		id: id,
    34  		v:  v,
    35  	}
    36  }
    37  
    38  // 边
    39  type edge struct {
    40  	sid int // 起点id
    41  	tid int // 目标id
    42  	//weight int // 权重
    43  }
    44  
    45  func newEdge(sid, tid int) *edge {
    46  	return &edge{
    47  		sid: sid,
    48  		tid: tid,
    49  	}
    50  }
    51  
    52  // 有向图
    53  type Graph struct {
    54  	adj   map[int]*vertex
    55  	edges map[int][]*edge // [顶点起点id]
    56  }
    57  
    58  func NewGraph() *Graph {
    59  	return &Graph{
    60  		adj:   make(map[int]*vertex),
    61  		edges: make(map[int][]*edge),
    62  	}
    63  }
    64  
    65  // 添加顶点
    66  func (g *Graph) AddVertex(id int, v interface{}) {
    67  	if !g.ContainsVertex(id) {
    68  		g.adj[id] = newVertex(id, v)
    69  	}
    70  }
    71  func (g *Graph) ContainsVertex(id int) bool {
    72  	_, ok := g.adj[id]
    73  	return ok
    74  }
    75  
    76  func (g *Graph) ContainsEdge(sid, tid int) bool {
    77  	if eds, ok := g.edges[sid]; ok {
    78  		for i := range eds {
    79  			if tid == eds[i].tid {
    80  				return true
    81  			}
    82  		}
    83  	}
    84  	return false
    85  }
    86  
    87  // 添加边
    88  func (g *Graph) AddEdge(sid, tid int) {
    89  	if g.ContainsVertex(sid) && g.ContainsVertex(tid) && sid != tid {
    90  		if !g.ContainsEdge(sid, tid) {
    91  			eds := g.edges[sid]
    92  			eds = append(eds, newEdge(sid, tid))
    93  			g.edges[sid] = eds
    94  		}
    95  	}
    96  }
    97  
    98  //拓扑排序中的 Kahn 算法  O(V+E)(V 表示顶点个数,E 表示边的个数)
    99  func topoSortKahn(g *Graph) []interface{} {
   100  	// 统计顶点入度
   101  	inDegree := make(map[int]int)
   102  	for id := range g.adj {
   103  		inDegree[id] = 0
   104  	}
   105  	for id := range g.adj {
   106  		if eds, ok := g.edges[id]; ok {
   107  			for i := range eds {
   108  				inDegree[eds[i].tid]++
   109  			}
   110  		}
   111  	}
   112  	que := queue.NewLinkedQueue()
   113  	for i := range inDegree {
   114  		if inDegree[i] == 0 { // 入度是0的添加进队列
   115  			que.Enqueue(i)
   116  		}
   117  	}
   118  	st := stack.NewArrayStack()
   119  	for !que.IsEmpty() {
   120  		id := que.Dequeue().(int)
   121  		st.Push(g.adj[id].v)
   122  		//fmt.Print("->", g.adj[id])
   123  		for _, v := range g.edges[id] {
   124  			inDegree[v.tid]-- //
   125  			if inDegree[v.tid] == 0 {
   126  				que.Enqueue(v.tid)
   127  			}
   128  		}
   129  	}
   130  	if st.Len() < len(g.adj) {
   131  		fmt.Println("有环图")
   132  	}
   133  	return st.ToSlice()
   134  }
   135  
   136  // DFS方式排序 时间复杂度 O(V+E)
   137  func topoSortDFS(g *Graph) {
   138  	// 创建逆邻接表
   139  	inverseAdj := make(map[int][]int, len(g.adj))
   140  	// 填充逆邻接表
   141  	for _, eds := range g.edges {
   142  		for i := range eds {
   143  			e := eds[i]
   144  			inverseAdj[e.tid] = append(inverseAdj[e.tid], e.sid)
   145  		}
   146  	}
   147  	visited := make(map[int]bool) // 访问记录
   148  	for v := range g.adj {
   149  		if !visited[v] {
   150  			visited[v] = true
   151  			dfs(v, inverseAdj, visited, g)
   152  		}
   153  	}
   154  	fmt.Println()
   155  }
   156  
   157  func dfs(vertex int, inverseAdj map[int][]int, visited map[int]bool, g *Graph) {
   158  	tids := inverseAdj[vertex]
   159  	for i := 0; i < len(tids); i++ {
   160  		tid := tids[i]
   161  		if visited[tid] {
   162  			continue
   163  		}
   164  		visited[tid] = true
   165  		dfs(tid, inverseAdj, visited, g)
   166  	}
   167  	fmt.Print("->", g.adj[vertex].v)
   168  }