79

golang有向无环图(dag)以及判断是否有环

 4 years ago
source link: https://blog.csdn.net/oqqYuan1234567890/article/details/104723305
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

有向无环图 邻接表实现

package main

import (
	"fmt"
	"github.com/eapache/queue"
)

// 邻接表
type Vertex struct {
	Key      string
	Parents  []*Vertex
	Children []*Vertex
	Value    interface{}
}

type DAG struct {
	Vertexes []*Vertex
}

func (dag *DAG) AddVertex(v *Vertex) {
	dag.Vertexes = append(dag.Vertexes, v)
}

func (dag *DAG) AddEdge(from, to *Vertex) {
	from.Children = append(from.Children, to)

	to.Parents = append(from.Parents, from)
}

func (dag *DAG) BFS(root *Vertex) {
	q := queue.New()

	visitMap := make(map[string]bool)
	visitMap[root.Key] = true

	q.Add(root)

	for {
		if q.Length() == 0 {
			fmt.Println("done")
			break
		}
		current := q.Remove().(*Vertex)

		fmt.Println("bfs key", current.Key)

		for _, v := range current.Children {
			fmt.Printf("from:%v to:%s\n", current.Key, v.Key)
			if v.Key == root.Key {
				panic("back root")
			}
			if _, ok := visitMap[v.Key]; !ok {
				visitMap[v.Key] = true
				//fmt.Println("add visit", v.Key)

				q.Add(v)
			}
		}
	}

}

func (dag *DAG) DFS(root *Vertex) {
	stack := []*Vertex{root}

	visitMap := make(map[string]bool)
	visitMap[root.Key] = true

	for i := 0; i < 10; i++ {
		if len(stack) == 0 {
			fmt.Println("done")
			break
		}
		if len(stack)-1 < 0 {
			panic("unexpected")
		}
		current := stack[len(stack)-1]
		stack = stack[:len(stack)-1]

		fmt.Println("dfs key", current.Key)

		for _, v := range current.Children {
			fmt.Println("from:%v to:%s", current.Key, v.Key)
			if v.Key == root.Key {
				panic("back root")
			}
			if _, ok := visitMap[v.Key]; !ok {
				visitMap[v.Key] = true
				//fmt.Println("add visit", v.Key)
				if v.Key == root.Key {
					panic("back root")
				}
				stack = append(stack, v)
			}
		}
	}

}

func main() {

	dag := &DAG{}
	v1 := &Vertex{Key: "1"}
	v2 := &Vertex{Key: "2"}
	v3 := &Vertex{Key: "3"}
	v4 := &Vertex{Key: "4"}
	v5 := &Vertex{Key: "5"}

	// dag
	//     5
	//   >
	//  /
	// 1----->2
	//  \   >   \
	//   > /     >
	//   3-------->4

	dag.AddEdge(v1, v5)
	dag.AddEdge(v1, v2)
	//dag.AddEdge(v2, v1)
	dag.AddEdge(v1, v3)
	dag.AddEdge(v3, v4)
	dag.AddEdge(v3, v2)
	dag.AddEdge(v2, v4)
	dag.BFS(v1)
	//dag.DFS(v1)

	
}

这里要说明一下,对于邻接表的数据结构,千万不要用json来序列化,因为邻接表的实现是有pointer loop问题的,而json包不会检查pointer loop

判断是否有环

一般来说,如果root顶点随着遍历如果会回到自身,那么这个图就是有环的,上面的例子
稍微改动一下

package main

import (
	"fmt"
	"github.com/eapache/queue"
)

// 邻接表
type Vertex struct {
	Key      string
	Parents  []*Vertex
	Children []*Vertex
	Value    interface{}
}

type DAG struct {
	Vertexes []*Vertex
}

func (dag *DAG) AddVertex(v *Vertex) {
	dag.Vertexes = append(dag.Vertexes, v)
}

func (dag *DAG) AddEdge(from, to *Vertex) {
	from.Children = append(from.Children, to)

	to.Parents = append(from.Parents, from)
}

func (dag *DAG) BFS(root *Vertex) {
	q := queue.New()

	visitMap := make(map[string]bool)
	visitMap[root.Key] = true

	q.Add(root)

	for {
		if q.Length() == 0 {
			fmt.Println("done")
			break
		}
		current := q.Remove().(*Vertex)

		fmt.Println("bfs key", current.Key)

		for _, v := range current.Children {
			fmt.Printf("from:%v to:%s\n", current.Key, v.Key)
			if v.Key == root.Key {
				panic("back root")
			}
			if _, ok := visitMap[v.Key]; !ok {
				visitMap[v.Key] = true
				//fmt.Println("add visit", v.Key)

				q.Add(v)
			}
		}
	}

}

func (dag *DAG) DFS(root *Vertex) {
	stack := []*Vertex{root}

	visitMap := make(map[string]bool)
	visitMap[root.Key] = true

	for i := 0; i < 10; i++ {
		if len(stack) == 0 {
			fmt.Println("done")
			break
		}
		if len(stack)-1 < 0 {
			panic("unexpected")
		}
		current := stack[len(stack)-1]
		stack = stack[:len(stack)-1]

		fmt.Println("dfs key", current.Key)

		for _, v := range current.Children {
			fmt.Println("from:%v to:%s", current.Key, v.Key)
			if v.Key == root.Key {
				panic("back root")
			}
			if _, ok := visitMap[v.Key]; !ok {
				visitMap[v.Key] = true
				//fmt.Println("add visit", v.Key)
				if v.Key == root.Key {
					panic("back root")
				}
				stack = append(stack, v)
			}
		}
	}

}

func main() {

	dag := &DAG{}
	v1 := &Vertex{Key: "1"}
	v2 := &Vertex{Key: "2"}
	v3 := &Vertex{Key: "3"}
	v4 := &Vertex{Key: "4"}
	v5 := &Vertex{Key: "5"}


	// 对于有环图,从root点出发,最终会回到root
	// non dag
	//    5
	//   >
	//  /
	// 1 <----2
	//  \   .>  \
	//   > /     >
	//    3----  >4
	dag.AddEdge(v1, v5)
	dag.AddEdge(v2, v1)
	dag.AddEdge(v1, v3)
	dag.AddEdge(v3, v4)
	dag.AddEdge(v3, v2)
	dag.AddEdge(v2, v4)
	dag.AddEdge(v2, v1)
	dag.BFS(v1)
	//dag.DFS(v1)
}

跟上面例子不一样,顶点2指向顶点1,也就是会有一个1->3->2>1的环
输出

bfs key 1
from:1 to:5
from:1 to:3
bfs key 5
bfs key 3
from:3 to:4
from:3 to:2
bfs key 4
bfs key 2
from:2 to:1
panic: back root

goroutine 1 [running]:
main.(*DAG).BFS(0xc00007cf38, 0xc0000ac000)
	/opt/go_work/src/mtest/dag/main.go:50 +0x4e3
main.main()
	/opt/go_work/src/mtest/dag/main.go:144 +0x53d
exit status 2

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK