├── .gitignore
├── 01_list
├── 00_img
│ └── 01_链表.drawio.svg
├── 01_list
│ ├── list.go
│ └── list_test.go
├── 02_lru
│ ├── lru.go
│ └── lru_test.go
└── 03_q1_list_bug
│ └── main.go
├── 02_array
├── 00_img
│ ├── 01_array.drawio.svg
│ └── 02_slice_struct.drawio.svg
├── 01_array_example
│ └── main.go
├── 02_slice
│ └── main.go
└── 03_q1_slice_cap
│ └── main.go
├── 03_stack
├── 00_img
│ └── 01_stack.drawio.svg
├── 01_array_stack
│ ├── stack.go
│ └── stack_test.go
├── 02_list_stack
│ ├── stack.go
│ └── stack_test.go
├── 03_calculation
│ ├── calculation.go
│ ├── calculation_test.go
│ ├── stack_int.go
│ └── stack_string.go
└── 04_defer
│ └── main.go
├── 99_others
├── GA
│ ├── GA.go
│ ├── GA_test.go
│ ├── doc.go
│ └── readme.md
├── Graph
│ ├── Graph.go
│ ├── Graph_test.go
│ ├── README.MD
│ └── test.txt
├── GraphMatrix
│ ├── GraphMatrix.go
│ ├── GraphMatrix_test.go
│ └── test.txt
└── ShortestPath
│ ├── Dijkstra
│ ├── Dijkstra.go
│ ├── Dijkstra.txt
│ └── Dijkstra_test.go
│ ├── Floyd
│ ├── Floyd.go
│ ├── Floyd.txt
│ └── Floyd_test.go
│ ├── README.MD
│ ├── SPFA
│ ├── SPFA.go
│ ├── SPFA_test.go
│ └── spfa.txt
│ └── doc.go
├── README.MD
├── go.mod
└── go.sum
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 | bin
--------------------------------------------------------------------------------
/01_list/00_img/01_链表.drawio.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/01_list/01_list/list.go:
--------------------------------------------------------------------------------
1 | package list
2 |
3 | import (
4 | "container/list"
5 | "sync"
6 | )
7 |
8 | // List 链表
9 | type List struct {
10 | *list.List
11 | mu sync.Mutex
12 | }
13 |
14 | // New 新建链表
15 | func New() *List {
16 | return &List{List: list.New()}
17 | }
18 |
19 | // PushBack 像链表尾部插入值
20 | func (l *List) PushBack(v interface{}) {
21 | l.mu.Lock()
22 | defer l.mu.Unlock()
23 | l.List.PushBack(v)
24 | }
25 |
--------------------------------------------------------------------------------
/01_list/01_list/list_test.go:
--------------------------------------------------------------------------------
1 | package list
2 |
3 | import (
4 | "container/list"
5 | "sync"
6 | "testing"
7 | )
8 |
9 | // TestList 测试标准库的链表
10 | // go test -race .
11 | func TestList(t *testing.T) {
12 | l := list.New()
13 | wg := sync.WaitGroup{}
14 | wg.Add(1)
15 | go func() {
16 | for i := 0; i < 10; i++ {
17 | l.PushBack(i)
18 | }
19 | wg.Done()
20 | }()
21 | l.PushBack(11)
22 | wg.Wait()
23 | }
24 |
25 | func TestList_PushBack(t *testing.T) {
26 | l := New()
27 | wg := sync.WaitGroup{}
28 | wg.Add(1)
29 | go func() {
30 | for i := 0; i < 10; i++ {
31 | l.PushBack(1)
32 | }
33 | wg.Done()
34 | }()
35 | l.PushBack(11)
36 | wg.Wait()
37 | }
38 |
--------------------------------------------------------------------------------
/01_list/02_lru/lru.go:
--------------------------------------------------------------------------------
1 | package lru
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | // Node 链表的节点
8 | type Node struct {
9 | prev, next *Node
10 |
11 | list *LRU
12 |
13 | key string
14 | value interface{}
15 | }
16 |
17 | // LRU 缓存
18 | type LRU struct {
19 | root *Node // 根节点
20 | cap int // 当前缓存容量
21 | len int // 缓存的长度
22 | }
23 |
24 | // NewLRU NewLRU
25 | func NewLRU(cap int) *LRU {
26 | l := &LRU{
27 | root: &Node{},
28 | cap: cap,
29 | }
30 | l.root.prev = l.root
31 | l.root.next = l.root
32 | l.root.list = l
33 | return l
34 | }
35 |
36 | // Get 获取缓存数据
37 | // 如果获取到数据,就把这个节点移动到链表头部
38 | // 如果没有获取到,就返回nil
39 | func (l *LRU) Get(key string) interface{} {
40 | defer l.debug()
41 | n := l.get(key)
42 | if n == nil {
43 | return nil
44 | }
45 |
46 | return n.value
47 | }
48 |
49 | func (l *LRU) get(key string) *Node {
50 | for n := l.root.next; n != l.root; n = n.next {
51 | if n.key == key {
52 | n.prev.next = n.next
53 | n.next.prev = n.prev
54 |
55 | n.next = l.root.next
56 | l.root.next.prev = n
57 | l.root.next = n
58 | n.prev = l.root
59 | return n
60 | }
61 | }
62 | return nil
63 | }
64 |
65 | // Put 写入缓存数据
66 | // 如果 key 已经存在,那么更新值
67 | // 如果 key 不存在,那么插入到第一个节点
68 | // 当缓存容量满了的时候,会自动删除最后的数据
69 | func (l *LRU) Put(key string, value interface{}) {
70 | defer l.debug()
71 | n := l.get(key)
72 | if n != nil {
73 | n.value = value
74 | return
75 | }
76 |
77 | // 缓存满了
78 | if l.len == l.cap {
79 | last := l.root.prev
80 | last.prev.next = l.root
81 | l.root.prev = last.prev
82 | last.list = nil
83 | last.prev = nil
84 | last.next = nil
85 | l.len--
86 | }
87 |
88 | node := &Node{key: key, value: value}
89 | head := l.root.next
90 | head.prev = node
91 | node.next = head
92 | node.prev = l.root
93 | l.root.next = node
94 | l.len++
95 | node.list = l
96 | }
97 |
98 | // debug for debug
99 | func (l *LRU) debug() {
100 | fmt.Println("lru len: ", l.len)
101 | fmt.Println("lru cap: ", l.cap)
102 | for n := l.root.next; n != l.root; n = n.next {
103 | fmt.Printf("%s:%v -> ", n.key, n.value)
104 | }
105 | fmt.Println()
106 | fmt.Println()
107 | }
108 |
--------------------------------------------------------------------------------
/01_list/02_lru/lru_test.go:
--------------------------------------------------------------------------------
1 | package lru
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | )
8 |
9 | func TestNewLRU(t *testing.T) {
10 | l := NewLRU(3)
11 | assert.Equal(t, l.Get(""), nil)
12 |
13 | l.Put("1", 1)
14 | l.Put("2", 2)
15 | l.Put("3", 3)
16 | assert.Equal(t, 3, l.Get("3"))
17 | assert.Equal(t, 1, l.Get("1"))
18 |
19 | l.Put("4", 4)
20 | assert.Equal(t, nil, l.Get("2"))
21 |
22 | l.Put("3", 31)
23 | assert.Equal(t, 31, l.Get("3"))
24 | }
25 |
--------------------------------------------------------------------------------
/01_list/03_q1_list_bug/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "container/list"
5 | "fmt"
6 | )
7 |
8 | func main() {
9 | l := list.List{}
10 | e := l.PushBack(10)
11 |
12 | l = list.List{}
13 | l.Remove(e)
14 | fmt.Println("list len: ", l.Len())
15 | }
16 |
--------------------------------------------------------------------------------
/02_array/00_img/01_array.drawio.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/02_array/00_img/02_slice_struct.drawio.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/02_array/01_array_example/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | )
7 |
8 | func main() {
9 | // 初始化数组
10 | var arr = [3]int{1, 2, 3}
11 | // 查找元素
12 | fmt.Printf("arr[1]: %d\n", arr[1])
13 | // 删除元素
14 | remove(&arr, 2)
15 | // remove(&arr, 3) // will panic
16 | fmt.Println(arr)
17 |
18 | fmt.Printf("main: %p --> %+v\n", &arr, arr)
19 | p(arr)
20 | p2(&arr)
21 | }
22 |
23 | // 删除数组 arr 的某个元素
24 | // index 为需要删除的索引
25 | // 从需要删除的元素开始,依次将后面的元素往前移动一位即可
26 | // 然后将最后一位修改为该类型的默认值
27 | func remove(arr *[3]int, index int) {
28 | if index >= len(arr) {
29 | log.Panicf("%d remove out range arr", index)
30 | }
31 | for i := index; i < len(arr)-1; i++ {
32 | arr[i] = arr[i+1]
33 | }
34 | arr[len(arr)-1] = 0
35 | }
36 |
37 | func p(arr [3]int) {
38 | fmt.Printf("p: %p --> %+v\n", &arr, arr)
39 | }
40 |
41 | func p2(arr *[3]int) {
42 | fmt.Printf("p2: %p --> %+v\n", arr, arr)
43 | }
44 |
--------------------------------------------------------------------------------
/02_array/02_slice/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | // 初始化
7 | s1 := make([]int, 2)
8 | fmt.Printf("s1(%p): %v, len: %d, cap: %d\n", &s1, s1, len(s1), cap(s1))
9 | // s1(0xc00000c080): [0 0], len: 2, cap: 2
10 |
11 | // 赋值
12 | s1[0] = 1
13 | s1[1] = 2
14 | fmt.Printf("s1(%p): %v, len: %d, cap: %d\n", &s1, s1, len(s1), cap(s1))
15 | // s1(0xc00000c080): [1 2], len: 2, cap: 2
16 |
17 | // 扩容
18 | s1 = append(s1, 3, 4, 5, 6, 7)
19 | fmt.Printf("s1(%p): %v, len: %d, cap: %d\n", &s1, s1, len(s1), cap(s1))
20 | // s1(0xc00000c080): [1 2 3], len: 3, cap: 4
21 |
22 | // 删除元素
23 | s1 = append(s1[:1], s1[2:]...)
24 | fmt.Printf("s1(%p): %v, len: %d, cap: %d\n", &s1, s1, len(s1), cap(s1))
25 | // s1(0xc00000c080): [1 3], len: 2, cap: 4
26 |
27 | // 复制一个 slice
28 | s2 := s1[:2]
29 | fmt.Printf("s2(%p): %v, len: %d, cap: %d\n", &s2, s2, len(s2), cap(s2))
30 | // s2(0xc00000c120): [1 3], len: 2, cap: 4
31 |
32 | s1[0] = 10 // 这里可以发现,s1[0] s2[0] 都被修改为了 10
33 | fmt.Printf("s1(%p): %v, len: %d, cap: %d\n", &s1, s1, len(s1), cap(s1))
34 | // s1(0xc00000c080): [10 3], len: 2, cap: 4
35 | fmt.Printf("s2(%p): %v, len: %d, cap: %d\n", &s2, s2, len(s2), cap(s2))
36 | // s2(0xc00000c120): [10 3], len: 2, cap: 4
37 |
38 | s1 = append(s1, 5, 6, 7, 8)
39 | s1[0] = 11 // 这里可以发现,s1[0] 被修改为了 11, s2[0] 还是10
40 | fmt.Printf("s1(%p): %v, len: %d, cap: %d\n", &s1, s1, len(s1), cap(s1))
41 | // s1(0xc00011c020): [11 3 5 6 7 8], len: 6, cap: 8
42 | fmt.Printf("s2(%p): %v, len: %d, cap: %d\n", &s2, s2, len(s2), cap(s2))
43 | // s2(0xc00011c0c0): [10 3], len: 2, cap: 4
44 |
45 | // 对比一下两种空 slice 的区别
46 | var s3 []int
47 | s4 := make([]int, 0)
48 | fmt.Printf("%p --> %#v\n", s3, s3) // 0x0 --> []int(nil)
49 | fmt.Printf("%p --> %#v\n", s4, s4) // 0x587450 --> []int{}
50 |
51 | initSlice()
52 | }
53 |
54 | func sliceChange(s []int) {
55 | // 不允许直接这么操作
56 | s[0] = 1
57 | }
58 |
59 | func initSlice() {
60 | var s1 []int
61 | fmt.Printf("%p: %v, len: %d, cap: %d\n", s1, s1, len(s1), cap(s1))
62 | s2 := make([]uint, 0)
63 | fmt.Printf("%p: %v, len: %d, cap: %d\n", s2, s2, len(s2), cap(s2))
64 | s3 := []int{}
65 | fmt.Printf("%p: %v, len: %d, cap: %d\n", s3, s3, len(s3), cap(s3))
66 | }
67 |
--------------------------------------------------------------------------------
/02_array/03_q1_slice_cap/main.go:
--------------------------------------------------------------------------------
1 | // Package main What will eventually be output?
2 | // A: 5 8 B: 8 8 C: 5 5 D: 5 6
3 | package main
4 |
5 | import (
6 | "fmt"
7 | )
8 |
9 | func main() {
10 | s := []int{1, 2}
11 | s = append(s, 3, 4, 5)
12 | fmt.Println(len(s), cap(s))
13 | }
14 |
--------------------------------------------------------------------------------
/03_stack/00_img/01_stack.drawio.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/03_stack/01_array_stack/stack.go:
--------------------------------------------------------------------------------
1 | package stack
2 |
3 | // Stack Stack
4 | type Stack struct {
5 | items []string
6 | current int
7 | }
8 |
9 | // NewStack NewStack
10 | func NewStack() *Stack {
11 | return &Stack{
12 | items: make([]string, 10),
13 | current: 0,
14 | }
15 | }
16 |
17 | // Push 入栈
18 | func (s *Stack) Push(item string) {
19 | s.current++
20 | // 判断底层 slice 是否满了,如果满了就 append
21 | if s.current == len(s.items) {
22 | s.items = append(s.items, item)
23 | return
24 | }
25 | s.items[s.current] = item
26 | }
27 |
28 | // Pop 出栈
29 | func (s *Stack) Pop() string {
30 | if s.current == 0 {
31 | return ""
32 | }
33 | item := s.items[s.current]
34 | s.current--
35 | return item
36 | }
37 |
--------------------------------------------------------------------------------
/03_stack/01_array_stack/stack_test.go:
--------------------------------------------------------------------------------
1 | package stack
2 |
3 | import (
4 | "strconv"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestNewStack(t *testing.T) {
11 | stack := NewStack()
12 | assert.Equal(t, "", stack.Pop())
13 | stack.Push("1")
14 | stack.Push("2")
15 | assert.Equal(t, "2", stack.Pop())
16 | assert.Equal(t, "1", stack.Pop())
17 | for i := 3; i < 20; i++ {
18 | stack.Push(strconv.Itoa(i))
19 | }
20 | assert.Equal(t, "19", stack.Pop())
21 | }
22 |
--------------------------------------------------------------------------------
/03_stack/02_list_stack/stack.go:
--------------------------------------------------------------------------------
1 | package stack
2 |
3 | // node 节点
4 | type node struct {
5 | prev, next *node
6 | value string
7 | }
8 |
9 | // Stack 链式栈
10 | type Stack struct {
11 | root *node
12 | len int
13 | }
14 |
15 | // NewStack NewStack
16 | func NewStack() *Stack {
17 | n := &node{}
18 | n.next = n
19 | n.prev = n
20 | return &Stack{root: n}
21 | }
22 |
23 | // Push 入栈
24 | func (s *Stack) Push(item string) {
25 | n := &node{value: item}
26 | s.root.prev.next = n
27 | n.prev = s.root.prev
28 | n.next = s.root
29 | s.root.prev = n
30 | s.len++
31 | }
32 |
33 | // Pop 出栈
34 | func (s *Stack) Pop() string {
35 | item := s.root.prev
36 | if item == s.root {
37 | return ""
38 | }
39 |
40 | s.root.prev = item.prev
41 | item.prev.next = s.root
42 | // 避免内存泄漏
43 | item.prev = nil
44 | item.next = nil
45 | s.len--
46 | return item.value
47 | }
48 |
--------------------------------------------------------------------------------
/03_stack/02_list_stack/stack_test.go:
--------------------------------------------------------------------------------
1 | package stack
2 |
3 | import (
4 | "strconv"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestNewStack(t *testing.T) {
11 | stack := NewStack()
12 | assert.Equal(t, "", stack.Pop())
13 | stack.Push("1")
14 | stack.Push("2")
15 | assert.Equal(t, "2", stack.Pop())
16 | assert.Equal(t, "1", stack.Pop())
17 | for i := 3; i < 20; i++ {
18 | stack.Push(strconv.Itoa(i))
19 | }
20 | assert.Equal(t, "19", stack.Pop())
21 | }
22 |
--------------------------------------------------------------------------------
/03_stack/03_calculation/calculation.go:
--------------------------------------------------------------------------------
1 | package calculation
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | )
7 |
8 | // 操作符的优先级
9 | var operatorPriority = map[string]int{
10 | "+": 0,
11 | "-": 0,
12 | "*": 1,
13 | "/": 1,
14 | "(": 2,
15 | ")": 2,
16 | }
17 |
18 | // Calculator 计算器
19 | type Calculator struct {
20 | nums *StackInt
21 | operators *Stack
22 | exp string
23 | }
24 |
25 | // NewCalculator NewCalculator
26 | func NewCalculator(exp string) *Calculator {
27 | return &Calculator{
28 | nums: NewStackInt(),
29 | operators: NewStack(),
30 | exp: exp,
31 | }
32 | }
33 |
34 | // Calculate 获取计算结果
35 | func (c *Calculator) Calculate() int {
36 | l := len(c.exp)
37 | for i := 0; i < l; i++ {
38 | switch e := (c.exp[i]); e {
39 | case ' ':
40 | continue
41 | case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
42 | // 一直往后获取数字,如果下一个还是数字说明这一个数还不完整
43 | j := i
44 | for j < l && c.exp[j] <= '9' && c.exp[j] >= '0' {
45 | j++
46 | }
47 | n, _ := strconv.Atoi(c.exp[i:j])
48 | i = j - 1
49 | c.nums.Push(n)
50 | case '+', '-', '*', '/':
51 | // 从计算符栈中获取栈顶元素,如果当前操作符的优先级低于栈顶元素的优先级
52 | // 并且栈顶元素不为空,和括号
53 | // 那么从数据栈中取两个数据和栈顶操作符进行计算
54 | pre := c.operators.Pop()
55 | for pre != "" && pre != "(" && operatorPriority[string(e)] <= operatorPriority[pre] {
56 | c.nums.Push(c.calc(pre))
57 | pre = c.operators.Pop()
58 | }
59 | if pre != "" {
60 | c.operators.Push(pre)
61 | }
62 | c.operators.Push(string(e))
63 | case '(':
64 | c.operators.Push(string(e))
65 | case ')':
66 | // 碰到右括号之后就一直不断操作符栈中弹出元素,并且取两个数据进行计算
67 | // 直到碰到左括号为止
68 | for o := c.operators.Pop(); o != "(" && o != ""; o = c.operators.Pop() {
69 | c.nums.Push(c.calc(o))
70 | }
71 | default:
72 | panic("invalid exp")
73 | }
74 | }
75 | // 最后如果不存在操作符,说明数据栈中的栈顶元素就是最后结果
76 | o := c.operators.Pop()
77 | if o == "" {
78 | return c.nums.Pop()
79 | }
80 | // 如果存在,就把最后的数据进行计算后返回
81 | return c.calc(o)
82 | }
83 |
84 | // calc 单次计算操作,o: 计算符
85 | func (c *Calculator) calc(o string) int {
86 | b := c.nums.Pop()
87 | a := c.nums.Pop()
88 |
89 | fmt.Printf("%d %s %d\n", a, o, b)
90 |
91 | switch o {
92 | case "+":
93 | return a + b
94 | case "-":
95 | return a - b
96 | case "*":
97 | return a * b
98 | case "/":
99 | return a / b
100 | }
101 |
102 | return 0
103 | }
104 |
105 | // calculate 计算器,支持加减乘除
106 | func calculate(s string) int {
107 | return NewCalculator(s).Calculate()
108 | }
109 |
--------------------------------------------------------------------------------
/03_stack/03_calculation/calculation_test.go:
--------------------------------------------------------------------------------
1 | package calculation
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func Test_calculate(t *testing.T) {
11 | tests := []struct {
12 | exp string
13 | want int
14 | }{
15 | {
16 | exp: " 2-1 + 2 ",
17 | want: 3,
18 | },
19 | {
20 | exp: "(1+(4+5+2)-3)+(6+8)",
21 | want: 23,
22 | },
23 | {
24 | exp: "(1+(4+5+2)-3)*(6+8)",
25 | want: 126,
26 | },
27 | {
28 | exp: "1-11",
29 | want: -10,
30 | },
31 | }
32 | for _, tt := range tests {
33 | t.Run(fmt.Sprintf("%s = %d", tt.exp, tt.want), func(t *testing.T) {
34 | assert.Equal(t, tt.want, calculate(tt.exp))
35 | })
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/03_stack/03_calculation/stack_int.go:
--------------------------------------------------------------------------------
1 | package calculation
2 |
3 | // StackInt StackInt
4 | type StackInt struct {
5 | items []int
6 | current int
7 | }
8 |
9 | // NewStackInt NewStackInt
10 | func NewStackInt() *StackInt {
11 | return &StackInt{
12 | items: make([]int, 10),
13 | current: 0,
14 | }
15 | }
16 |
17 | // Push 入栈
18 | func (s *StackInt) Push(item int) {
19 | s.current++
20 | // 判断底层 slice 是否满了,如果满了就 append
21 | if s.current == len(s.items) {
22 | s.items = append(s.items, item)
23 | return
24 | }
25 | s.items[s.current] = item
26 | }
27 |
28 | // Pop 出栈
29 | func (s *StackInt) Pop() int {
30 | if s.current == 0 {
31 | return 0
32 | }
33 | item := s.items[s.current]
34 | s.current--
35 | return item
36 | }
37 |
--------------------------------------------------------------------------------
/03_stack/03_calculation/stack_string.go:
--------------------------------------------------------------------------------
1 | package calculation
2 |
3 | // Stack Stack
4 | type Stack struct {
5 | items []string
6 | current int
7 | }
8 |
9 | // NewStack NewStack
10 | func NewStack() *Stack {
11 | return &Stack{
12 | items: make([]string, 10),
13 | current: 0,
14 | }
15 | }
16 |
17 | // Push 入栈
18 | func (s *Stack) Push(item string) {
19 | s.current++
20 | // 判断底层 slice 是否满了,如果满了就 append
21 | if s.current == len(s.items) {
22 | s.items = append(s.items, item)
23 | return
24 | }
25 | s.items[s.current] = item
26 | }
27 |
28 | // Pop 出栈
29 | func (s *Stack) Pop() string {
30 | if s.current == 0 {
31 | return ""
32 | }
33 | item := s.items[s.current]
34 | s.current--
35 | return item
36 | }
37 |
--------------------------------------------------------------------------------
/03_stack/04_defer/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "fmt"
4 |
5 | func main() {
6 | f0()
7 | f1()
8 | f2()
9 |
10 | fmt.Println("f3:", f3())
11 | fmt.Println("f4:", f4())
12 |
13 | f5()
14 | }
15 |
16 | // 基本用法:延迟调用,清理资源
17 | func f0() {
18 | defer fmt.Println("clean")
19 | fmt.Println("hello")
20 | }
21 |
22 | // 基本用法1: 后进先出
23 | func f1() {
24 | defer fmt.Println("1")
25 | defer fmt.Println("2")
26 |
27 | fmt.Println("3")
28 | }
29 |
30 | // 基本用法2:异常恢复
31 | func f2() {
32 | defer func() {
33 | if err := recover(); err != nil {
34 | fmt.Printf("paniced: %+v", err)
35 | }
36 | }()
37 | panic("test")
38 | }
39 |
40 | // 容易掉坑1:函数变量修改
41 | func f3() (res int) {
42 | defer func() {
43 | res++
44 | }()
45 | return 0
46 | }
47 |
48 | // 容易掉坑之2:参数复制
49 | func f4() (res int) {
50 | defer func(res int) {
51 | res++
52 | }(res)
53 | return 0
54 | }
55 |
56 | // 容易掉坑3:值
57 | func f5() {
58 | i := 0
59 | defer fmt.Println(i)
60 | i++
61 | return
62 | }
63 |
64 | // 循环defer不可取
65 | func f6() {
66 | for i := 0; i < 10; i++ {
67 | defer func() {
68 | fmt.Printf("f6: %d\n", i)
69 | }()
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/99_others/GA/GA.go:
--------------------------------------------------------------------------------
1 | package GA
2 |
3 | import (
4 | "fmt"
5 | "math"
6 | "math/rand"
7 | "time"
8 | )
9 |
10 | var (
11 | groupSize int //种群大小
12 | chromosomeSize int //染色体长度
13 | selectRand float64 //轮盘选择概率
14 | crossRand float64 //交叉概率
15 | mutationRand float64 //变异概率
16 | group []Person //种群
17 | bestPerson Person //当前最好的个体
18 | r *rand.Rand
19 | )
20 |
21 | //Person 个体
22 | type Person struct {
23 | chromosome []int //染色体
24 | value float64 //适应值
25 | }
26 |
27 | //Init 初始化函数
28 | //初始化设置种群大小、轮盘选择概率、交叉概率已经变异的概率
29 | func Init(GroupSize, ChromosomeSize int, SelectRand, CrossRand, MutationRand float64) {
30 | groupSize = GroupSize
31 | crossRand = CrossRand
32 | selectRand = SelectRand
33 | mutationRand = MutationRand
34 | chromosomeSize = ChromosomeSize
35 | r = rand.New(rand.NewSource(time.Now().UnixNano()))
36 | bestPerson.chromosome = make([]int, chromosomeSize)
37 | }
38 |
39 | //InitGroup 初始化种群
40 | //根据种群大小随机产生一些个体填充
41 | func InitGroup() {
42 | group = make([]Person, groupSize)
43 | for i := 0; i < groupSize; i++ {
44 | group[i].chromosome = make([]int, chromosomeSize)
45 | for j := 0; j < chromosomeSize; j++ {
46 | if r.Float64() > selectRand {
47 | group[i].chromosome[j] = 1
48 | }
49 | }
50 | }
51 | }
52 |
53 | //Fitness 计算适应值
54 | func Fitness(person Person) float64 {
55 | x := decode(person)
56 | return x + 10*math.Sin(5*x) + 7*math.Cos(4*x)
57 | }
58 |
59 | //解码
60 | func decode(person Person) float64 {
61 | var sum float64
62 | //解码
63 | for i := 0; i < chromosomeSize; i++ {
64 | //二进制染色体转十进制值
65 | if person.chromosome[i] == 1 {
66 | sum = sum + math.Pow(2.0, float64(i))
67 | }
68 | }
69 | return sum * 9 / (math.Pow(2.0, 14.0) - 1)
70 | }
71 |
72 | //Select 选择
73 | func Select() {
74 | newGroup := make([]Person, groupSize)
75 | for i := 0; i < groupSize; i++ {
76 | newGroup[i].chromosome = make([]int, chromosomeSize)
77 | rnd := r.Float64()
78 |
79 | A:
80 | for j := 0; j < groupSize; j++ {
81 | if group[j].value > rnd*bestPerson.value {
82 | copy(newGroup[i].chromosome, group[j].chromosome)
83 | break A
84 | }
85 | if j == groupSize-1 {
86 | copy(newGroup[i].chromosome, bestPerson.chromosome)
87 | }
88 | }
89 | }
90 | group = newGroup
91 | newGroup = nil
92 | }
93 |
94 | //Cross 交叉
95 | func Cross() {
96 | for i := 0; i < groupSize; i = i + 2 {
97 | if r.Float64() < crossRand {
98 | crossPosition := r.Intn(chromosomeSize - 1)
99 | if crossPosition == 0 || crossPosition == 1 {
100 | continue
101 | }
102 | //交叉
103 | for j := crossPosition; j < chromosomeSize; j++ {
104 | tmp := group[i].chromosome[j]
105 | group[i].chromosome[j] = group[i+1].chromosome[j]
106 | group[i+1].chromosome[j] = tmp
107 | }
108 | }
109 | }
110 | }
111 |
112 | //Mutation 变异
113 | func Mutation() {
114 | for i := 0; i < groupSize; i++ {
115 | if r.Float64() < mutationRand {
116 | mutationPosition := r.Intn(chromosomeSize - 1)
117 |
118 | //单点变异
119 | if group[i].chromosome[mutationPosition] == 0 {
120 | group[i].chromosome[mutationPosition] = 1
121 | } else {
122 | group[i].chromosome[mutationPosition] = 0
123 | }
124 | }
125 | }
126 | }
127 |
128 | //GA 遗传算法
129 | func GA() {
130 | //初始化
131 | Init(100, 14, 0.5, 0.6, 0.05)
132 | //初始化种群
133 | InitGroup()
134 |
135 | //遗传循环
136 | for i := 0; i < 1000; i++ {
137 |
138 | //计算适应值
139 | for j := 0; j < groupSize; j++ {
140 | group[j].value = Fitness(group[j])
141 |
142 | //保存当前最好的个体
143 | if group[j].value > bestPerson.value {
144 | copy(bestPerson.chromosome, group[j].chromosome)
145 | bestPerson.value = group[j].value
146 | }
147 | }
148 |
149 | fmt.Println("第", i, "代最好个体:", bestPerson.value, " ", decode(bestPerson))
150 |
151 | //选择
152 | Select()
153 |
154 | //交叉
155 | Cross()
156 |
157 | //变异
158 | Mutation()
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/99_others/GA/GA_test.go:
--------------------------------------------------------------------------------
1 | package GA
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func Test(t *testing.T) {
8 | GA()
9 | }
10 |
--------------------------------------------------------------------------------
/99_others/GA/doc.go:
--------------------------------------------------------------------------------
1 | //Package GA 遗传算法的Golang实现
2 | //遗传算法的计算流程 编码->获得初始群体->计算适应值->产生新的群体(选择、交叉、变异等)->满足要求->解码->获得近似解
3 | //例子:求解函数 f(x) = x + 10*sin(5*x) + 7*cos(4*x) 在区间[0,9]的最大值。
4 | //假设求解精度为3,那么需要求解的值可能为 0.000-9.000 可能性在2^13-2^14这个范围之内
5 | //使用一个14为的二进制字符串即可表示,最终的求解域
6 | //解码 f(x), x∈[lower_bound, upper_bound] x = lower_bound + decimal(chromosome)×(upper_bound-lower_bound)/( 2 ^chromosome_size- 1 )
7 | package GA
8 |
--------------------------------------------------------------------------------
/99_others/GA/readme.md:
--------------------------------------------------------------------------------
1 | # 遗传算法
2 |
3 |
--------------------------------------------------------------------------------
/99_others/Graph/Graph.go:
--------------------------------------------------------------------------------
1 | //Package Graph 邻接表
2 | package Graph
3 |
4 | import (
5 | "bufio"
6 | "io"
7 | "os"
8 | "strconv"
9 | "strings"
10 | )
11 |
12 | // EdgeType 边的权值类型
13 | type EdgeType int
14 |
15 | // VextexType 顶点类型定义
16 | type VextexType int
17 |
18 | // VextexDataType 顶点值类型定义
19 | type VextexDataType int
20 |
21 | //EdgeNode 边的节点
22 | type EdgeNode struct {
23 | Weight EdgeType //权值
24 | V VextexType //指向储存该顶点的下标
25 | Next *EdgeNode //指向下一条边
26 | }
27 |
28 | //VextexNode 顶点节点定义
29 | type VextexNode struct {
30 | data VextexDataType //顶点的值
31 | FisrtEdge *EdgeNode //该顶点指向的第一条边
32 | }
33 |
34 | //Graph 图
35 | type Graph struct {
36 | VNum, ENum int //顶点数目,边数目
37 | G []VextexNode //邻接表
38 | }
39 |
40 | //CreateGraph 创建邻接表
41 | func CreateGraph(VNum int) (graph Graph) {
42 | graph.VNum = VNum
43 | graph.G = make([]VextexNode, VNum)
44 | for i := 0; i < VNum; i++ {
45 | graph.G[i] = VextexNode{}
46 | }
47 | return graph
48 | }
49 |
50 | //AddEdge 添加边
51 | func (graph Graph) AddEdge(s, t VextexType, weight EdgeType) {
52 | edge := &EdgeNode{V: t, Weight: weight}
53 |
54 | //添加边到头部
55 | edge.Next = graph.G[s].FisrtEdge
56 | graph.G[s].FisrtEdge = edge
57 | }
58 |
59 | //BuildGraph 通过读取文件建图
60 | //文件格式要求:
61 | //顶点个数 边数
62 | //顶点v1 顶点V2 边的权重
63 | //...
64 | func BuildGraph(path string) (graph Graph) {
65 | f, err := os.Open(path)
66 | if err != nil {
67 | panic(err)
68 | }
69 | buf := bufio.NewReader(f)
70 |
71 | i := 0
72 | //边的数目
73 | for {
74 | line, err := buf.ReadString('\n')
75 | if err != nil {
76 | if err == io.EOF {
77 | return graph
78 | }
79 | panic(err)
80 | }
81 | line = strings.TrimSpace(line)
82 | data := strings.Split(line, " ")
83 | if i == 0 {
84 | n, err := strconv.Atoi(data[0])
85 | if err != nil {
86 | panic(err)
87 | }
88 | graph = CreateGraph(n)
89 |
90 | graph.ENum, err = strconv.Atoi(data[1])
91 | if err != nil {
92 | panic(err)
93 | }
94 | } else if i <= graph.ENum {
95 | s, err := strconv.Atoi(data[0])
96 | if err != nil {
97 | panic(err)
98 | }
99 | t, err := strconv.Atoi(data[1])
100 | if err != nil {
101 | panic(err)
102 | }
103 | weight, err := strconv.Atoi(data[2])
104 | if err != nil {
105 | panic(err)
106 | }
107 | graph.AddEdge(VextexType(s), VextexType(t), EdgeType(weight))
108 | }
109 | i++
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/99_others/Graph/Graph_test.go:
--------------------------------------------------------------------------------
1 | package Graph
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestGraph(t *testing.T) {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/99_others/Graph/README.MD:
--------------------------------------------------------------------------------
1 | Graph
2 | ====
3 |
4 | 邻接表法建图
--------------------------------------------------------------------------------
/99_others/Graph/test.txt:
--------------------------------------------------------------------------------
1 | 3 3
2 | 0 1 1
3 | 0 2 2
4 | 1 2 3
5 |
--------------------------------------------------------------------------------
/99_others/GraphMatrix/GraphMatrix.go:
--------------------------------------------------------------------------------
1 | //Package GraphMatrix 邻接矩阵表示图
2 | package GraphMatrix
3 |
4 | import (
5 | "bufio"
6 | "io"
7 | "os"
8 | "strconv"
9 | "strings"
10 | )
11 |
12 | // EdgeType 边的权值类型
13 | type EdgeType int
14 |
15 | //INF 无穷大
16 | const INF = 0xfffff
17 |
18 | //Graph 图
19 | type Graph struct {
20 | VNum, ENum int //顶点、边的个数
21 | G [][]EdgeType //邻接矩阵
22 | }
23 |
24 | //CreateGraph 创建一个图并且初始化邻接矩阵
25 | func CreateGraph(n int) (graph Graph) {
26 | graph = Graph{VNum: n}
27 | graph.G = make([][]EdgeType, n)
28 | for i := 0; i < n; i++ {
29 | graph.G[i] = make([]EdgeType, n)
30 | for j := 0; j < n; j++ {
31 | graph.G[i][j] = INF
32 | if i == j {
33 | graph.G[i][j] = 0
34 | }
35 | }
36 | }
37 | return graph
38 | }
39 |
40 | //BuildGraph 创建图
41 | func BuildGraph(path string) (graph Graph) {
42 | f, err := os.Open(path)
43 | if err != nil {
44 | panic(err)
45 | }
46 | buf := bufio.NewReader(f)
47 |
48 | i := 0
49 | //边的数目
50 | for {
51 | line, err := buf.ReadString('\n')
52 | if err != nil {
53 | if err == io.EOF {
54 | return graph
55 | }
56 | panic(err)
57 | }
58 | line = strings.TrimSpace(line)
59 | data := strings.Split(line, " ")
60 | if i == 0 {
61 | n, err := strconv.Atoi(data[0])
62 | if err != nil {
63 | panic(err)
64 | }
65 | graph = CreateGraph(n)
66 |
67 | graph.ENum, err = strconv.Atoi(data[1])
68 | if err != nil {
69 | panic(err)
70 | }
71 | } else if i <= graph.ENum {
72 | s, err := strconv.Atoi(data[0])
73 | if err != nil {
74 | panic(err)
75 | }
76 | t, err := strconv.Atoi(data[1])
77 | if err != nil {
78 | panic(err)
79 | }
80 | weight, err := strconv.Atoi(data[2])
81 | if err != nil {
82 | panic(err)
83 | }
84 |
85 | //有向图,如果是无向图再添加一条反向边
86 | graph.G[s][t] = EdgeType(weight)
87 | }
88 | i++
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/99_others/GraphMatrix/GraphMatrix_test.go:
--------------------------------------------------------------------------------
1 | package GraphMatrix
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | func TestGraph(t *testing.T) {
9 | graph := BuildGraph("test.txt")
10 | fmt.Println(graph)
11 | }
12 |
--------------------------------------------------------------------------------
/99_others/GraphMatrix/test.txt:
--------------------------------------------------------------------------------
1 | 3 3
2 | 0 1 1
3 | 0 2 2
4 | 1 2 3
5 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/Dijkstra/Dijkstra.go:
--------------------------------------------------------------------------------
1 | package Diijkstra
2 |
3 | import (
4 | "errors"
5 |
6 | "container/list"
7 |
8 | "github.com/mohuishou/algorithm/Graph"
9 | )
10 |
11 | //INF 无穷大
12 | const INF = 0xffffff
13 |
14 | //Dijkstra 算法
15 | //一种求单源最短路径的算法
16 | func Dijkstra(graph Graph.Graph, s Graph.VextexType, dist []Graph.EdgeType, path []Graph.VextexType) {
17 | //标记顶点是否曾经入队
18 | visited := make([]bool, graph.VNum)
19 | //初始化
20 | for i := 0; i < graph.VNum; i++ {
21 | dist[i] = INF //距离为无穷大
22 | path[i] = -1 //没有上一个节点
23 | visited[i] = false
24 | }
25 | path[s] = s
26 | dist[s] = 0
27 |
28 | //使用list实现一个队列操作
29 | q := list.New()
30 |
31 | //将点s入队
32 | q.PushBack(s)
33 | for q.Len() != 0 {
34 | u := q.Front().Value.(Graph.VextexType)
35 | q.Remove(q.Front())
36 | //如果该点周围的点已经走过,则无需再走
37 | if visited[u] {
38 | continue
39 | }
40 |
41 | //将该点加入已观察
42 | visited[u] = true
43 |
44 | e := graph.G[u].FisrtEdge
45 |
46 | for e != nil {
47 | //这条边下的顶点
48 | v := e.V
49 |
50 | //如果该点尚未走过,并且当前点的距离加上边的距离小于之前该点的距离,那么就更新该点的距离
51 | if visited[v] == false && dist[v] > dist[u]+e.Weight {
52 | dist[v] = dist[u] + e.Weight //更新该点距离
53 | path[v] = u //更新父节点
54 | q.PushBack(v) //将该点入队
55 | }
56 | e = e.Next
57 | }
58 |
59 | }
60 |
61 | }
62 |
63 | //GetPathForDijkstra 通过路径获得到指定目的节点的路径
64 | func GetPathForDijkstra(path []Graph.VextexType, t Graph.VextexType) ([]Graph.VextexType, error) {
65 | tPath := make([]Graph.VextexType, 0)
66 | for {
67 | tPath = append(tPath, t)
68 | if path[t] == -1 {
69 | return nil, errors.New("不存在到该节点的路径")
70 | }
71 | if t == path[t] {
72 | return tPath, nil
73 | }
74 | t = path[t]
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/Dijkstra/Dijkstra.txt:
--------------------------------------------------------------------------------
1 | 5 9
2 | 0 1 10
3 | 0 2 3
4 | 1 2 1
5 | 2 1 4
6 | 1 3 2
7 | 2 3 8
8 | 2 4 2
9 | 3 4 7
10 | 4 3 9
11 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/Dijkstra/Dijkstra_test.go:
--------------------------------------------------------------------------------
1 | package Diijkstra
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/mohuishou/algorithm/Graph"
8 | )
9 |
10 | func TestDijkstra(t *testing.T) {
11 | graph := Graph.BuildGraph("Dijkstra.txt")
12 | path := make([]Graph.VextexType, graph.VNum)
13 | dist := make([]Graph.EdgeType, graph.VNum)
14 | Dijkstra(graph, 0, dist, path)
15 | tPath, err := GetPathForDijkstra(path, 1)
16 | if err != nil {
17 | t.Fatal(err)
18 | }
19 | checkDist := []Graph.EdgeType{0, 7, 3, 9, 5}
20 | checkPath := []Graph.VextexType{1, 2, 0}
21 |
22 | fmt.Println("expected dist is \t\t", checkDist)
23 | fmt.Println("the value of dist is \t\t", dist)
24 | fmt.Println("expected path is \t\t", checkPath)
25 | fmt.Println("the value of path is \t\t", tPath)
26 |
27 | if len(checkPath) != len(tPath) || len(dist) != len(checkDist) {
28 | t.Fail()
29 | }
30 |
31 | for i := len(checkPath) - 1; i >= 0; i-- {
32 | if checkPath[i] != tPath[i] {
33 | t.Fail()
34 | }
35 | }
36 |
37 | for i := len(dist) - 1; i >= 0; i-- {
38 | if checkDist[i] != dist[i] {
39 | t.Fail()
40 | }
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/Floyd/Floyd.go:
--------------------------------------------------------------------------------
1 | package Floyd
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/mohuishou/algorithm/GraphMatrix"
7 | )
8 |
9 | //Floyd 求取多源最短路径
10 | func Floyd(graph GraphMatrix.Graph, dist [][]GraphMatrix.EdgeType, path [][]int) error {
11 | for i := 0; i < graph.VNum; i++ {
12 | for j := 0; j < graph.VNum; j++ {
13 | path[i][j] = -1
14 | dist[i][j] = graph.G[i][j]
15 | }
16 | }
17 |
18 | for k := 0; k < graph.VNum; k++ {
19 | for i := 0; i < graph.VNum; i++ {
20 | for j := 0; j < graph.VNum; j++ {
21 |
22 | //找到更短的路径
23 | if dist[i][k]+dist[k][j] < dist[i][j] {
24 | dist[i][j] = dist[i][k] + dist[k][j]
25 |
26 | //发现负值圈
27 | if i == j && dist[i][j] < 0 {
28 | return errors.New("存在负值圈")
29 | }
30 | path[i][j] = k
31 | }
32 | }
33 | }
34 | }
35 | return nil
36 | }
37 |
38 | //GetPathForFloyd 获取路径
39 | func GetPathForFloyd(path [][]int, s, t int) (tPath []int) {
40 | tPath = make([]int, 1)
41 | tPath[0] = s
42 | for {
43 | s = path[s][t]
44 | if s == -1 || s == t {
45 | tPath = append(tPath, t)
46 | return tPath
47 | }
48 | tPath = append(tPath, s)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/Floyd/Floyd.txt:
--------------------------------------------------------------------------------
1 | 4 8
2 | 0 1 5
3 | 1 0 50
4 | 1 3 5
5 | 1 2 15
6 | 2 0 30
7 | 2 3 15
8 | 3 2 5
9 | 3 0 15
10 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/Floyd/Floyd_test.go:
--------------------------------------------------------------------------------
1 | package Floyd
2 |
3 | import (
4 | "testing"
5 |
6 | "fmt"
7 |
8 | "github.com/mohuishou/algorithm/GraphMatrix"
9 | )
10 |
11 | func TestFolyd(t *testing.T) {
12 | graph := GraphMatrix.BuildGraph("Floyd.txt")
13 | dist := make([][]GraphMatrix.EdgeType, graph.VNum)
14 | path := make([][]int, graph.VNum)
15 | for i := 0; i < graph.VNum; i++ {
16 | path[i] = make([]int, graph.VNum)
17 | dist[i] = make([]GraphMatrix.EdgeType, graph.VNum)
18 | }
19 | Floyd(graph, dist, path)
20 |
21 | fmt.Println("test result:")
22 | fmt.Print("source -> dest \t")
23 | fmt.Print("dist \t\t")
24 | fmt.Print("path \t\t\n")
25 |
26 | for i := 0; i < graph.VNum; i++ {
27 | for j := 0; j < graph.VNum; j++ {
28 | if i == j {
29 | continue
30 | }
31 | fmt.Print(i, " -> ", j, " \t\t")
32 | fmt.Print(dist[i][j], " \t\t")
33 | tPath := GetPathForFloyd(path, i, j)
34 | for i := 0; i < len(tPath); i++ {
35 | fmt.Print(tPath[i])
36 | if i < len(tPath)-1 {
37 | fmt.Print("->")
38 | }
39 | }
40 | fmt.Print("\t\t\n")
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/README.MD:
--------------------------------------------------------------------------------
1 | 最短路径问题
2 | ====
3 |
4 | - Dijkstra
5 | - Floyd
6 | - SPFA
--------------------------------------------------------------------------------
/99_others/ShortestPath/SPFA/SPFA.go:
--------------------------------------------------------------------------------
1 | package SPFA
2 |
3 | import (
4 | "container/list"
5 |
6 | "errors"
7 |
8 | "github.com/mohuishou/algorithm/Graph"
9 | )
10 |
11 | //INF 定义一个无穷大的数
12 | const INF = 0xfffff
13 |
14 | var (
15 | graph Graph.Graph //图
16 | s Graph.VextexType //需要查找的顶点
17 | dist []Graph.EdgeType //各顶点到s的最短路径
18 | path []Graph.VextexType //路径集合
19 | visited []bool //标记顶点是否在队列当中
20 | count []int //统计,用于判断负环
21 | isInit bool //是否初始化
22 | )
23 |
24 | //Init 初始化
25 | func Init(g Graph.Graph, S Graph.VextexType, Dist []Graph.EdgeType, Path []Graph.VextexType) {
26 | graph = g
27 | s = S
28 | dist = Dist
29 | path = Path
30 | //标记顶点是否在队列当中
31 | visited = make([]bool, graph.VNum)
32 |
33 | //统计,用于判断负环
34 | count = make([]int, graph.VNum)
35 |
36 | //初始化
37 | for i := 0; i < graph.VNum; i++ {
38 | dist[i] = INF //所有的dist为无穷远,即为不可达
39 | path[i] = -1 //所有的上级节点为-1,即为无上级节点
40 | visited[i] = false // 所有都尚未观察
41 | }
42 |
43 | //先将源点入队
44 | dist[s] = 0
45 | path[s] = s
46 | visited[s] = true
47 | count[s] = 1
48 |
49 | isInit = true
50 | }
51 |
52 | //DFS spfa算法dfs实现
53 | func DFS(u Graph.VextexType) error {
54 | if isInit != true {
55 | return errors.New("请先执行SPFA.Init方法")
56 | }
57 | visited[u] = true
58 | e := graph.G[u].FisrtEdge
59 | for e != nil {
60 | v := e.V
61 | if dist[v] > dist[u]+e.Weight {
62 | dist[v] = dist[u] + e.Weight //更新该点距离
63 | path[v] = u //更新父节点
64 | if visited[v] == false {
65 | count[v]++
66 | if count[v] > graph.VNum {
67 | return errors.New("存在负环!")
68 | }
69 |
70 | //注意DFS的结果不能直接return,直接return的时候回溯的时候就没有办法在上一级重新找值了
71 | err := DFS(v)
72 | if err != nil {
73 | return err
74 | }
75 | } else {
76 | return nil
77 | }
78 | }
79 | e = e.Next
80 | }
81 | visited[u] = false
82 | return nil
83 | }
84 |
85 | //BFS spfa算法bfs实现,负环判断不太稳定
86 | func BFS() error {
87 | if isInit != true {
88 | return errors.New("请先执行SPFA.Init方法")
89 | }
90 |
91 | q := list.New()
92 | q.PushBack(s)
93 |
94 | //循环跳出条件:队列为空
95 | for q.Len() != 0 {
96 | u := q.Front().Value.(Graph.VextexType)
97 | q.Remove(q.Front())
98 |
99 | //释放对点u的标记
100 | visited[u] = false
101 |
102 | e := graph.G[u].FisrtEdge
103 |
104 | for e != nil {
105 | //这条边下的顶点
106 | v := e.V
107 |
108 | //如果当前点的距离加上边的距离小于之前该点的距离,那么就更新该点的距离
109 | if dist[v] > dist[u]+e.Weight {
110 | dist[v] = dist[u] + e.Weight //更新该点距离
111 | path[v] = u //更新父节点
112 |
113 | //如果顶点不在队内,则将顶点入队
114 | if visited[v] == false {
115 | q.PushBack(v) //将该点入队
116 | visited[v] = true
117 | count[v]++
118 |
119 | //出现负环,报错
120 | if count[v] > graph.VNum {
121 | return errors.New("存在负环!")
122 | }
123 | }
124 | }
125 | e = e.Next
126 | }
127 |
128 | }
129 | return nil
130 | }
131 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/SPFA/SPFA_test.go:
--------------------------------------------------------------------------------
1 | package SPFA
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 |
7 | "github.com/mohuishou/algorithm/Graph"
8 | )
9 |
10 | func TestBFS(t *testing.T) {
11 | graph := Graph.BuildGraph("spfa.txt")
12 | path := make([]Graph.VextexType, graph.VNum)
13 | dist := make([]Graph.EdgeType, graph.VNum)
14 | Init(graph, 0, dist, path)
15 | err := BFS()
16 | if err != nil {
17 | t.Fatal(err)
18 | }
19 | fmt.Println(dist)
20 | }
21 |
22 | func TestDFS(t *testing.T) {
23 | graph := Graph.BuildGraph("spfa.txt")
24 | path := make([]Graph.VextexType, graph.VNum)
25 | dist := make([]Graph.EdgeType, graph.VNum)
26 | Init(graph, 0, dist, path)
27 | err := DFS(s)
28 | if err != nil {
29 | t.Fatal(err)
30 | }
31 |
32 | fmt.Println(dist)
33 | }
34 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/SPFA/spfa.txt:
--------------------------------------------------------------------------------
1 | 5 9
2 | 0 1 10
3 | 0 2 3
4 | 1 2 1
5 | 2 1 4
6 | 1 3 2
7 | 2 3 8
8 | 2 4 2
9 | 3 4 7
10 | 4 3 9
11 |
--------------------------------------------------------------------------------
/99_others/ShortestPath/doc.go:
--------------------------------------------------------------------------------
1 | // Package ShortestPath 最短路径算法实现
2 | // 包含三种常用的最短路径算法
3 | // Dijkstra算法
4 | // Floyd算法
5 | // SPFA算法
6 | package ShortestPath
7 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # Go 数据结构与算法系列
2 |
3 | > Go 数据结构与算法系列文章,本系列文章主要会包括常见的数据结构与算法实现,同时会包括 Go 标准库代码的分析理解,讲到对应章节的时候优先学习分析 Go 的源码实现,例如 slice、list、sort 等,然后可能会有一些常见的案例实现,同时这也是 极客时间-数据结构与算法之美 的课程笔记
4 |
5 | | 标题 | Github | 博客 |
6 | | ---- | --------- | ------------------------------------------------------------------------------------------------- |
7 | | 链表 | [list](./01_list) | [Go 数据结构与算法 01-链表(深入理解 container/list&LRU 缓存的实现)](https://lailin.xyz/post/list.html) |
8 | | 数组 | [array](./02_array) | [Go数据结构与算法02-数组: 深入理解 slice](https://lailin.xyz/post/array.html)
[Go数据结构与算法03-数组下: 使用 GDB 调试 Golang 代码](https://lailin.xyz/post/array_2.html) |
9 | | 栈 | [stack](./03_stack) | [Go数据结构与算法04-栈上: 如何实现一个计算器](https://lailin.xyz/post/stack.html)
[Go数据结构与算法05-栈下: 深入理解 defer](https://lailin.xyz/post/defer.html) |
10 |
11 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/mohuishou/go-algorithm
2 |
3 | go 1.15
4 |
5 | require (
6 | github.com/mohuishou/algorithm v0.0.0-20170417061216-79e9994e74e5
7 | github.com/stretchr/testify v1.6.1
8 | )
9 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/mohuishou/algorithm v0.0.0-20170417061216-79e9994e74e5 h1:IVCUKsTr7l07IDF2sH/9NkYD7lvj+vul6G+yLNn+aQM=
4 | github.com/mohuishou/algorithm v0.0.0-20170417061216-79e9994e74e5/go.mod h1:xbrAXLmb467SPTTV211zL8r//shKKXzBiEPRnUHR7h0=
5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
8 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
9 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
12 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
14 |
--------------------------------------------------------------------------------