数据结构代码

1.稀疏数组

当一个数组中大部分元素为0或者同为一个值时,可以用稀疏数组保存。即只记录不同的值。

第一个值一般记录原始大小。

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. )
  7. const (
  8. BLACK_CHESS = 1 // 黑子
  9. WIHTE_CHESS = 2 // 白子
  10. FILE_NAME = "data.json"
  11. )
  12. type ValNode struct {
  13. Row int `json:"row"`
  14. Col int `json:"col"`
  15. Val int `json:"val"`
  16. }
  17. // 稀疏数组
  18. func main() {
  19. var chessMap [10][10]int
  20. chessMap[1][5] = BLACK_CHESS
  21. chessMap[2][3] = WIHTE_CHESS
  22. chessMap[4][6] = BLACK_CHESS
  23. chessMap[7][9] = WIHTE_CHESS
  24. for _, v := range chessMap {
  25. for _, v2 := range v {
  26. fmt.Printf("%d\t", v2)
  27. }
  28. fmt.Println()
  29. }
  30. var sparseArr []ValNode
  31. // 第一个结构体记录原始数组的大小
  32. sparseArr = append(sparseArr, ValNode{Row: len(chessMap), Col: len(chessMap[0]), Val: 0})
  33. for r, v := range chessMap {
  34. for c, v2 := range v {
  35. if v2 != 0 {
  36. valNode := ValNode{Row: r, Col: c, Val: v2}
  37. sparseArr = append(sparseArr, valNode)
  38. }
  39. }
  40. }
  41. // 打印
  42. for _, node := range sparseArr {
  43. fmt.Println(node)
  44. }
  45. // 存到文件,用json格式
  46. j, err := json.Marshal(sparseArr)
  47. if err != nil {
  48. fmt.Println(err)
  49. return
  50. }
  51. err = ioutil.WriteFile(FILE_NAME, j, 0666)
  52. if err != nil {
  53. fmt.Println(err)
  54. return
  55. }
  56. // 恢复
  57. b, err := ioutil.ReadFile(FILE_NAME)
  58. if err != nil {
  59. fmt.Println(err)
  60. return
  61. }
  62. var sparseSlice []ValNode
  63. err = json.Unmarshal(b, &sparseSlice)
  64. if err != nil {
  65. fmt.Println(err)
  66. return
  67. }
  68. fmt.Println("恢复后的棋盘")
  69. for _, sp := range sparseSlice {
  70. fmt.Println(sp)
  71. }
  72. }

2.环形队列

  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. /**
  7. 环形队列
  8. 思路:
  9. 1.创建一个数组,设置最大值
  10. 2.一个指向队首的指针front和一个指向队尾的指针real,初始化为0
  11. 3.提供三个方法:push,pop和show
  12. 4.当push的时候,real 指针往后移
  13. 5.pop的时候front指针往后移
  14. 6.当两个指针重合的时候,就空了
  15. 7.当real指针加一取模后等于头就满了
  16. 实际容量是数组容量减一
  17. */
  18. type CircleQueue struct {
  19. MaxSize int // 最大数量
  20. Array [5]int // slice
  21. Head int // 指向队首
  22. Tail int // 指向队尾
  23. }
  24. // 加入队列
  25. func (queue *CircleQueue) Push(val int) error {
  26. if queue.IsFull() {
  27. return errors.New("queue is full")
  28. }
  29. queue.Array[queue.Tail] = val
  30. queue.Tail = (queue.Tail + 1) % queue.MaxSize
  31. return nil
  32. }
  33. // 弹出
  34. func (queue *CircleQueue) Pop() (val int, err error) {
  35. if queue.IsEmpty() {
  36. return 0, errors.New("queue is empty")
  37. }
  38. val = queue.Array[queue.Head]
  39. queue.Head = (queue.Head + 1) % queue.MaxSize
  40. return val, nil
  41. }
  42. // 显示队列
  43. func (queue *CircleQueue) ShowQueue() {
  44. size := queue.Size()
  45. if size == 0 {
  46. fmt.Println("queue is empty")
  47. return
  48. }
  49. var tempHead = queue.Head
  50. for i := 0; i < size; i++ {
  51. fmt.Printf("arr[%d]=%d\t", tempHead, queue.Array[tempHead])
  52. tempHead = (tempHead + 1) % queue.MaxSize
  53. }
  54. fmt.Println()
  55. }
  56. // 判断队列已满
  57. func (queue *CircleQueue)IsFull() bool {
  58. return (queue.Tail + 1) % queue.MaxSize == queue.Head
  59. }
  60. // 是否为空
  61. func (queue *CircleQueue) IsEmpty() bool {
  62. return queue.Head == queue.Tail
  63. }
  64. // 有多少个元素
  65. func (queue *CircleQueue) Size() int {
  66. return (queue.Tail - queue.Head + queue.MaxSize) % queue.MaxSize
  67. }
  68. func main() {
  69. // 队列
  70. circleQueue := CircleQueue{MaxSize: 5}
  71. circleQueue.ShowQueue()
  72. err := circleQueue.Push(1)
  73. ifError(err)
  74. err = circleQueue.Push(4)
  75. ifError(err)
  76. err = circleQueue.Push(6)
  77. ifError(err)
  78. err = circleQueue.Push(5)
  79. ifError(err)
  80. err = circleQueue.Push(7)
  81. ifError(err)
  82. circleQueue.ShowQueue()
  83. err = circleQueue.Push(7)
  84. ifError(err)
  85. v, err := circleQueue.Pop()
  86. ifError(err)
  87. fmt.Printf("pop value=%d\n", v)
  88. circleQueue.ShowQueue()
  89. }
  90. func ifError(err error) {
  91. if err != nil {
  92. fmt.Println(err)
  93. }
  94. }

3.单链表

一般来说,为了比较好的对单链表进行增删改查,我们会给它设置一个头节点,主要作用是标识链表头,而且不存放数据。

用链表实现队列更方便,效率更高。

  1. package main
  2. import "fmt"
  3. // 单链表
  4. type HeroNode struct {
  5. no int
  6. name string
  7. nickName string
  8. next *HeroNode // 指向下一个节点
  9. }
  10. // 直接在最后插入
  11. func insertLast(head *HeroNode, new *HeroNode) {
  12. temp := head
  13. for {
  14. if temp.next == nil { // 如果找到最后则跳出
  15. break
  16. }
  17. temp = temp.next // 不断指向下一个节点
  18. }
  19. temp.next = new
  20. }
  21. // 排序插入,根据no的大小
  22. func insertSort(head *HeroNode, new *HeroNode) {
  23. temp := head
  24. flag := true
  25. // 比较新节点和temp的下一个节点
  26. for {
  27. if temp.next == nil { // 到了链表最后
  28. break
  29. } else if new.no < temp.next.no {
  30. // new 应该插入到temp的下一个
  31. break
  32. } else if new.no == temp.next.no {
  33. flag = false
  34. }
  35. temp = temp.next // 不断指向下一个节点
  36. }
  37. if !flag {
  38. fmt.Println("对不起,节点已经存在,no=", new.no)
  39. return
  40. } else {
  41. // 插入节点
  42. new.next = temp.next
  43. temp.next = new
  44. }
  45. }
  46. // 删除一个节点
  47. // no : 删除的number
  48. func deleteNode(head *HeroNode, no int) {
  49. temp := head
  50. finded := false
  51. for {
  52. if temp.next == nil { // 到了链表最后
  53. break
  54. } else if no == temp.next.no {
  55. finded = true
  56. break
  57. }
  58. temp = temp.next // 不断指向下一个节点
  59. }
  60. if finded {
  61. temp.next = temp.next.next
  62. } else {
  63. fmt.Println("没有找到")
  64. }
  65. }
  66. func showAll(head *HeroNode) {
  67. temp := head
  68. // 先判断是不是空链表
  69. if temp.next == nil {
  70. fmt.Println("空空如也")
  71. return
  72. }
  73. // 遍历链表
  74. for {
  75. fmt.Printf("[%d, %s, %s]->", temp.next.no, temp.next.name, temp.next.nickName)
  76. temp = temp.next
  77. if temp.next == nil {
  78. break
  79. }
  80. }
  81. fmt.Println()
  82. }
  83. func main() {
  84. head := HeroNode{}
  85. node1 := HeroNode{no: 1, name: "宋江", nickName: "及时雨"}
  86. node2 := HeroNode{no: 2, name: "吴用", nickName: "智多星"}
  87. node3 := HeroNode{no: 3, name: "林冲", nickName: "豹子头"}
  88. node4 := HeroNode{no: 4, name: "X", nickName: "x"}
  89. //insertLast(&head, &node2)
  90. //insertLast(&head, &node3)
  91. //insertLast(&head, &node1)
  92. insertSort(&head, &node2)
  93. insertSort(&head, &node4)
  94. insertSort(&head, &node3)
  95. insertSort(&head, &node1)
  96. showAll(&head)
  97. deleteNode(&head, 3)
  98. showAll(&head)
  99. }

还有 双向链表环形链表,先放一放,估计也很少用到。

4. 栈

应用场景:

  1. 子程序调用:在跳往子程序前,会将下个指令的地址保存在栈中,直到子程序执行完,再从栈中取出;
  2. 处理递归调用;
  3. 表达式的求值与转换;
  4. 二叉树遍历;
  5. 图形的深度优先搜索法。
  1. package chapter2
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. // 实现一个栈
  7. // 出栈、入栈、遍历
  8. type Stack struct {}
  9. var arr [5]int // 用数组实现栈
  10. var pointer = -1 // 位置指针
  11. // 出栈
  12. func (this *Stack) Pop() (val int, err error){
  13. if pointer < 0 {
  14. return -1, errors.New("stack is empty")
  15. }
  16. val = arr[pointer]
  17. pointer -= 1
  18. return val, nil
  19. }
  20. // 入栈
  21. func (this *Stack) Push(val int) {
  22. if pointer >= len(arr)-1 {
  23. fmt.Println("stack is full")
  24. return
  25. }
  26. pointer += 1
  27. arr[pointer] = val
  28. }
  29. // 遍历
  30. func (this *Stack) List() {
  31. if pointer < 0 {
  32. fmt.Println("stack is empty")
  33. return
  34. }
  35. fmt.Println("stack list:")
  36. for i := pointer; i >= 0; i-- {
  37. fmt.Println(arr[i])
  38. }
  39. }

表达式求值思路:

  1. 用两个栈,一个保存数,一个保存操作符;
  2. 如果已经入栈的操作符优先级比要入栈的低,那么先计算