Go 算法和数据结构

刷题过程中会遇到一些通用数据结构的封装,在这里记录一下。注意因为是刷算法题用的,没有考虑 goroutine 安全, 不要直接用在并发环境,如果是在生产环境中使用请加锁改造。(没有泛型写起来挺繁琐的)

Stack

  1. type Stack struct {
  2. st []int
  3. }
  4. func NewStack() *Stack {
  5. return &Stack{st:make([]int,0)}
  6. }
  7. func (s *Stack) Push(x int) {
  8. s.st = append(s.st, x)
  9. }
  10. func (s *Stack) Peek() int{
  11. return s.st[len(s.st)-1]
  12. }
  13. func (s *Stack) Pop() int{
  14. n := len(s.st)
  15. top := s.st[n-1]
  16. s.st = s.st[:n-1]
  17. return top
  18. }
  19. func (s *Stack) Empty() bool{
  20. return len(s.st) == 0
  21. }

Queue

  1. type Item struct {
  2. Num int
  3. Order int
  4. }
  5. type Queue struct {
  6. items []Item
  7. }
  8. func NewQueue() *Queue {
  9. return &Queue{
  10. items: make([]Item, 0),
  11. }
  12. }
  13. func (q *Queue) Push(x Item) {
  14. q.items = append(q.items, x)
  15. }
  16. func (q *Queue) Pop() Item {
  17. x := q.items[0]
  18. q.items = q.items[1:]
  19. return x
  20. }
  21. func (q *Queue) Front() Item {
  22. return q.items[0]
  23. }
  24. func (q *Queue) End() Item {
  25. return q.items[len(q.items)-1]
  26. }
  27. func (q *Queue) Empty() bool {
  28. return len(q.items) == 0
  29. }

Deque

  1. import (
  2. "container/list"
  3. "fmt"
  4. )
  5. // 滑动窗口最大值
  6. type Deque struct {
  7. ll *list.List
  8. }
  9. func NewDeque() *Deque {
  10. return &Deque{ll: list.New()}
  11. }
  12. func (dq *Deque) PushFront(x int) {
  13. dq.ll.PushFront(x)
  14. }
  15. func (dq *Deque) PushBack(x int) {
  16. dq.ll.PushBack(x)
  17. }
  18. func (dq *Deque) Pop() { // remove back
  19. dq.ll.Remove(dq.ll.Back())
  20. }
  21. func (dq *Deque) PopFront() { // remove first
  22. dq.ll.Remove(dq.ll.Front())
  23. }
  24. func (dq *Deque) Front() int {
  25. return dq.ll.Front().Value.(int)
  26. }
  27. func (dq *Deque) Back() int {
  28. return dq.ll.Back().Value.(int)
  29. }
  30. func (dq *Deque) Len() int {
  31. return dq.ll.Len()
  32. }

Linked List

  1. package main
  2. import "fmt"
  3. // 测试链表。在 redigo 里边使用到了链表作为 pool 的实现
  4. type IntList struct {
  5. count int
  6. // front,back 分别指向第一个和最后一个 node,或者是 nil。front.prev back.next 都是空
  7. front, back *Node
  8. }
  9. // 链表节点
  10. type Node struct {
  11. next, prev *Node
  12. }
  13. func (l *IntList) Count() int {
  14. return l.count
  15. }
  16. func (l *IntList) pushFront(node *Node) {
  17. node.next = l.front
  18. node.prev = nil
  19. if l.count == 0 { // note when list is empty
  20. l.back = node
  21. } else {
  22. l.front.prev = node
  23. }
  24. l.front = node
  25. l.count++
  26. }
  27. func (l *IntList) popFront() {
  28. first := l.front
  29. l.count--
  30. if l.count == 0 {
  31. l.front, l.back = nil, nil
  32. } else {
  33. first.next.prev = nil
  34. l.front = first.next
  35. }
  36. first.next, first.prev = nil, nil // clear first
  37. }
  38. func (l *IntList) popBack() {
  39. last := l.back
  40. l.count--
  41. if l.count == 0 {
  42. l.front, l.back = nil, nil
  43. } else {
  44. last.prev.next = nil
  45. l.back = last.prev
  46. }
  47. last.prev, last.next = nil, nil
  48. }
  49. func (l *IntList) Print() {
  50. cur := l.front
  51. for cur != l.back {
  52. fmt.Println(cur)
  53. cur = cur.next
  54. }
  55. if l.back != nil {
  56. fmt.Println(l.back)
  57. }
  58. }

Trie

  1. // Package main provides ...
  2. package main
  3. import "fmt"
  4. // https://golangbyexample.com/trie-implementation-in-go/
  5. const (
  6. ALBHABET_SIZE = 26
  7. )
  8. type node struct {
  9. childrens [ALBHABET_SIZE]*node
  10. isWordEnd bool
  11. }
  12. type trie struct {
  13. root *node
  14. }
  15. func newTrie() *trie {
  16. return &trie{
  17. root: &node{},
  18. }
  19. }
  20. func (t *trie) insert(word string) {
  21. wordLength := len(word)
  22. current := t.root
  23. for i := 0; i < wordLength; i++ {
  24. idx := word[i] - 'a'
  25. if current.childrens[idx] == nil {
  26. current.childrens[idx] = &node{}
  27. }
  28. current = current.childrens[idx]
  29. }
  30. current.isWordEnd = true
  31. }
  32. func (t *trie) find(word string) bool {
  33. wordLength := len(word)
  34. current := t.root
  35. for i := 0; i < wordLength; i++ {
  36. idx := word[i] - 'a'
  37. if current.childrens[idx] == nil {
  38. return false
  39. }
  40. current = current.childrens[idx]
  41. }
  42. if current.isWordEnd {
  43. return true
  44. }
  45. return false
  46. }
  47. func main() {
  48. trie := newTrie()
  49. words := []string{"zhang", "wang", "li", "zhao"}
  50. for i := 0; i < len(words); i++ {
  51. trie.insert(words[i])
  52. }
  53. toFind := []string{"zhang", "wang", "li", "zhao", "gong"}
  54. for i := 0; i < len(toFind); i++ {
  55. c := toFind[i]
  56. if trie.find(c) {
  57. fmt.Printf("word[%s] found in trie.\n", c)
  58. } else {
  59. fmt.Printf("word[%s] not found in trie\n", c)
  60. }
  61. }
  62. }

OrderedMap (类似 python collections.OrderedDict)

模拟 python collections.OrderedDict 写的,可以方便的实现 lru 等

  1. package main
  2. import (
  3. "container/list"
  4. "fmt"
  5. )
  6. // 按照 key 插入顺序遍历 map,类似 python collections.OrderedDict。注意不是 key 的字典序,而是插入顺序
  7. type OrderedMap struct {
  8. m map[string]int
  9. me map[string]*list.Element
  10. ll *list.List // 记录 key order
  11. }
  12. func NewOrderedMap() *OrderedMap {
  13. return &OrderedMap{
  14. m: make(map[string]int),
  15. me: make(map[string]*list.Element),
  16. ll: list.New(),
  17. }
  18. }
  19. func (o *OrderedMap) Set(k string, v int) {
  20. if _, found := o.m[k]; !found {
  21. e := o.ll.PushBack(k)
  22. o.me[k] = e
  23. }
  24. o.m[k] = v
  25. }
  26. func (o *OrderedMap) Exist(k string) bool {
  27. _, found := o.m[k]
  28. return found
  29. }
  30. func (o *OrderedMap) Get(k string) int {
  31. return o.m[k]
  32. }
  33. func (o *OrderedMap) Delete(k string) {
  34. delete(o.m, k)
  35. node := o.me[k]
  36. o.ll.Remove(node)
  37. delete(o.me, k)
  38. }
  39. func (o *OrderedMap) Len() int {
  40. return len(o.m)
  41. }
  42. // 按照 key 进入顺序返回
  43. func (o *OrderedMap) Keys() []string {
  44. keys := make([]string, o.ll.Len())
  45. i := 0
  46. for e := o.ll.Front(); e != nil; e = e.Next() {
  47. keys[i] = e.Value.(string)
  48. i++
  49. }
  50. return keys
  51. }