缘起

最近阅读<<我的第一本算法书>>(【日】石田保辉;宫崎修一)
本系列笔记拟采用golang练习之

链表

  1. 链表是数据结构之一,其中的数据呈线性排列。
  2. 每个数据节点都有1个“指针”,它指向下一个数据的内存地址。
  3. 访问数据时,我们需要从链表头部开始查找(线性查找),
  4. 如果目标数据在链表最后的话,需要的时间就是O(n)。
  5. 另外,添加数据只需要更改两个指针的指向,所以耗费的时间与n无关。
  6. 如果已经到达了添加数据的位置,那么添加操作只需花费O(1)的时间。
  7. 删除数据同样也只需O(1)的时间。
  8. 摘自 <<我的第一本算法书>>(【日】石田保辉;宫崎修一)

目标

  • 实现一个链表, 提供与数组类似的线性访问接口

设计

  • ILinkedList: 链表接口
  • IListIterator: 链表迭代器接口
  • tLinkedList: 链表, 实现ILinkedList接口
  • tListIterator: 链表迭代器, 实现IListIterator接口

单元测试

linked_list_test.go

  1. package data_structure
  2. import (
  3. "fmt"
  4. "learning/gooop/data_structure/linked_list"
  5. "strings"
  6. "testing"
  7. )
  8. func Test_LinkedList(t *testing.T) {
  9. fnAssertTrue := func(b bool, msg string) {
  10. if !b {
  11. panic(msg)
  12. }
  13. }
  14. list := linked_list.NewLinkedList()
  15. state := list.String()
  16. t.Log(state)
  17. fnAssertTrue(state == "h=nil,t=nil,s=0", "expecting empty list")
  18. list.Append(0)
  19. state = list.String()
  20. t.Log(state)
  21. fnAssertTrue(state == "h=0,t=0,s=1,0", "expecting [0]")
  22. list.Append(1)
  23. state = list.String()
  24. t.Log(state)
  25. fnAssertTrue(state == "h=0,t=1,s=2,0,1", "expecting [0,1]")
  26. e,it := list.Get(0)
  27. t.Log(it)
  28. fnAssertTrue(e == nil, "expecting e == nil")
  29. fnAssertTrue(it == 0, "expecting 0")
  30. e,it = list.Get(1)
  31. t.Log(it)
  32. fnAssertTrue(e == nil, "expecting e == nil")
  33. fnAssertTrue(it == 1, "expecting 1")
  34. e = list.Set(0, 10)
  35. state = list.String()
  36. t.Log(state)
  37. fnAssertTrue(e == nil, "expecting e == nil")
  38. fnAssertTrue(state == "h=10,t=1,s=2,10,1", "expecting [10,1]")
  39. e = list.Set(1, 20)
  40. state = list.String()
  41. t.Log(state)
  42. fnAssertTrue(e == nil, "expecting e == nil")
  43. fnAssertTrue(state == "h=10,t=20,s=2,10,20", "expecting [10,20]")
  44. e = list.Remove(1)
  45. state = list.String()
  46. t.Log(state)
  47. fnAssertTrue(e == nil, "expecting e == nil")
  48. fnAssertTrue(state == "h=10,t=10,s=1,10", "expecting [10]")
  49. e = list.Remove(0)
  50. state = list.String()
  51. t.Log(state)
  52. fnAssertTrue(e == nil, "expecting e == nil")
  53. fnAssertTrue(state == "h=nil,t=nil,s=0", "expecting []")
  54. e = list.Insert(0, 0)
  55. state = list.String()
  56. t.Log(state)
  57. fnAssertTrue(e == nil, "expecting e == nil")
  58. fnAssertTrue(state == "h=0,t=0,s=1,0", "expecting [0]")
  59. e = list.Insert(1, 1)
  60. state = list.String()
  61. t.Log(state)
  62. fnAssertTrue(e == nil, "expecting e == nil")
  63. fnAssertTrue(state == "h=0,t=1,s=2,0,1", "expecting [0,1]")
  64. e = list.Insert(3, 3)
  65. t.Log(e)
  66. fnAssertTrue(e != nil, "expecting e != nil")
  67. e = list.Insert(-1, -1)
  68. t.Log(e)
  69. fnAssertTrue(e != nil, "expecting e != nil")
  70. items := make([]string, 0)
  71. for iter := list.Iterator();iter.More(); {
  72. e,v := iter.Next()
  73. fnAssertTrue(e == nil, "expecting e == nil")
  74. items = append(items, fmt.Sprintf("%v", v))
  75. }
  76. state = strings.Join(items, ",")
  77. t.Log(state)
  78. fnAssertTrue(state == "0,1", "expecting [0,1]")
  79. }

测试输出

  1. $ go test -v linked_list_test.go
  2. === RUN Test_LinkedList
  3. linked_list_test.go:19: h=nil,t=nil,s=0
  4. linked_list_test.go:24: h=0,t=0,s=1,0
  5. linked_list_test.go:29: h=0,t=1,s=2,0,1
  6. linked_list_test.go:33: 0
  7. linked_list_test.go:38: 1
  8. linked_list_test.go:44: h=10,t=1,s=2,10,1
  9. linked_list_test.go:50: h=10,t=20,s=2,10,20
  10. linked_list_test.go:56: h=10,t=10,s=1,10
  11. linked_list_test.go:62: h=nil,t=nil,s=0
  12. linked_list_test.go:68: h=0,t=0,s=1,0
  13. linked_list_test.go:74: h=0,t=1,s=2,0,1
  14. linked_list_test.go:79: index out of bounds
  15. linked_list_test.go:83: index out of bounds
  16. linked_list_test.go:93: 0,1
  17. --- PASS: Test_LinkedList (0.00s)
  18. PASS
  19. ok command-line-arguments 0.002s

ILinkedList.go

链表接口

  1. package linked_list
  2. type ILinkedList interface {
  3. Size() int
  4. IsEmpty() bool
  5. IsNotEmpty() bool
  6. Get(i int) (error,interface{})
  7. Set(i int, it interface{}) error
  8. Append(it interface{})
  9. Remove(i int) error
  10. Insert(i int, it interface{}) error
  11. Iterator() IListIterator
  12. String() string
  13. }

IListIterator.go

链表迭代器接口

  1. package linked_list
  2. type IListIterator interface {
  3. More() bool
  4. Next() (error,interface{})
  5. }

tLinkedList.go

链表, 实现ILinkedList接口

  1. package linked_list
  2. import (
  3. "errors"
  4. "fmt"
  5. "strings"
  6. )
  7. type tLinkedList struct {
  8. head *tLinkedNode
  9. tail *tLinkedNode
  10. size int
  11. }
  12. type tLinkedNode struct {
  13. value interface{}
  14. next *tLinkedNode
  15. }
  16. var gIndexOutofBoundsError = errors.New("index out of bounds")
  17. func NewLinkedList() ILinkedList {
  18. return &tLinkedList{
  19. head: nil,
  20. tail: nil,
  21. size: 0,
  22. }
  23. }
  24. func newLinkedNode(value interface{}) *tLinkedNode {
  25. return &tLinkedNode{
  26. value,nil,
  27. }
  28. }
  29. func (me *tLinkedList) Size() int {
  30. return me.size
  31. }
  32. func (me *tLinkedList) IsEmpty() bool {
  33. return me.size <= 0
  34. }
  35. func (me *tLinkedList) IsNotEmpty() bool {
  36. return !me.IsEmpty()
  37. }
  38. func (me *tLinkedList) Get(i int) (error,interface{}) {
  39. e,_,node := me.getNodeAt(i)
  40. if e != nil {
  41. return e, nil
  42. }
  43. return e,node.value
  44. }
  45. func (me *tLinkedList) getNodeAt(i int) (err error, prev *tLinkedNode, node *tLinkedNode) {
  46. if i >= me.size || i < 0 {
  47. return gIndexOutofBoundsError, nil, nil
  48. }
  49. n := 0
  50. prev = nil
  51. node = me.head
  52. for {
  53. if n >= i {
  54. return nil, prev, node
  55. }
  56. if node == nil {
  57. return gIndexOutofBoundsError, nil, nil
  58. }
  59. n++
  60. prev = node
  61. node = node.next
  62. }
  63. }
  64. func (me *tLinkedList) Set(i int, value interface{}) error {
  65. e,prev,node := me.getNodeAt(i)
  66. if e != nil {
  67. return e
  68. }
  69. nn := newLinkedNode(value)
  70. if prev == nil {
  71. me.head = nn
  72. } else {
  73. prev.next = nn
  74. }
  75. nn.next = node.next
  76. if nn.next == nil {
  77. me.tail = nn
  78. }
  79. return nil
  80. }
  81. func (me *tLinkedList) Append(value interface{}) {
  82. nn := newLinkedNode(value)
  83. t := me.tail
  84. if t == nil {
  85. me.head = nn
  86. } else {
  87. t.next = nn
  88. }
  89. me.tail = nn
  90. me.size++
  91. }
  92. func (me *tLinkedList) Remove(i int) error {
  93. e,prev,node := me.getNodeAt(i)
  94. if e != nil {
  95. return e
  96. }
  97. if prev != nil {
  98. prev.next = node.next
  99. } else {
  100. me.head = node.next
  101. }
  102. if node.next == nil {
  103. me.tail = prev
  104. } else {
  105. me.tail = node.next
  106. }
  107. me.size--
  108. return nil
  109. }
  110. func (me *tLinkedList) Insert(i int, value interface{}) error {
  111. nn := newLinkedNode(value)
  112. if i == me.size {
  113. // always allow inserting tail
  114. t := me.tail
  115. me.tail = nn
  116. if t != nil {
  117. t.next = nn
  118. }
  119. if me.head == nil {
  120. me.head = nn
  121. }
  122. me.size++
  123. return nil
  124. }
  125. e,prev,node := me.getNodeAt(i)
  126. if e != nil {
  127. return e
  128. }
  129. if prev == nil {
  130. me.head = nn
  131. } else {
  132. prev.next = nn
  133. }
  134. nn.next = node
  135. me.size++
  136. return nil
  137. }
  138. func (me *tLinkedList) Iterator() IListIterator {
  139. items := make([]interface{}, me.size)
  140. i := 0
  141. for node := me.head;; {
  142. if node == nil {
  143. break
  144. }
  145. items[i] = node.value
  146. node = node.next
  147. i++
  148. }
  149. return newListIterator(items)
  150. }
  151. func (me *tLinkedList) String() string {
  152. items := make([]string, 0)
  153. if me.head == nil {
  154. items = append(items, "h=nil")
  155. } else {
  156. items = append(items, fmt.Sprintf("h=%v", me.head.value))
  157. }
  158. if me.tail == nil {
  159. items = append(items, "t=nil")
  160. } else {
  161. items = append(items, fmt.Sprintf("t=%v", me.tail.value))
  162. }
  163. items = append(items, fmt.Sprintf("s=%v", me.size))
  164. for node:=me.head;node != nil; {
  165. items = append(items, fmt.Sprintf("%v", node.value))
  166. node = node.next
  167. }
  168. return strings.Join(items, ",")
  169. }

tListIterator.go

链表迭代器, 实现IListIterator接口

  1. package linked_list
  2. type tListIterator struct {
  3. items []interface{}
  4. count int
  5. pos int
  6. }
  7. func newListIterator(items []interface{}) IListIterator {
  8. size := len(items)
  9. copy := make([]interface{}, size)
  10. for i,it := range items {
  11. copy[i] = it
  12. }
  13. return &tListIterator{
  14. items: copy,
  15. count: size,
  16. pos: 0,
  17. }
  18. }
  19. func (me *tListIterator) More() bool {
  20. return me.pos < me.count
  21. }
  22. func (me *tListIterator) Next() (error,interface{}) {
  23. if me.pos >= me.count {
  24. return gIndexOutofBoundsError, nil
  25. }
  26. n := me.pos
  27. me.pos++
  28. return nil, me.items[n]
  29. }

(end)