github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/docs/003-container包源码分析.md (about)

     1  
     2  ## Container  容器数据类型
     3  
     4  Container 主要实现了三个数据结构: 堆, 链表, 环 
     5  
     6  [分析示例:coding/container](../coding/container)
     7  
     8  [源码位置:/src/container](../go/src/container)
     9  
    10  ### Heap  最小堆
    11  
    12  Heap 包定义了堆的实现接口,提供了 堆接口Push, Pop 并继承sort.Interface 的 Len, Less, Swap接口 , 所以实现一个最小堆, 需要实现上面五个接口; 
    13  
    14  需要注意, Pop 时, heap 接口会先将堆顶堆尾数据交换,所以实现 Pop 接口时,读取堆顶元素,实际是读取数组的最后一个元素 
    15  
    16  Heap 主要提供了以下方法列表 
    17  
    18  h 是自定义数据结构的指针
    19  
    20  - heap.Init(h) 初始化最小堆 
    21  
    22  - heap.Push(h) 向堆中添加数据 
    23  
    24  - heap.Pop(h) 删除并返回堆顶数据
    25  
    26  - heap.Remove(h, i) 删除第i个数据元素
    27  
    28  - heap.Fix(h, i) 在外部修改了i元素值后, Fix重新堆化, 调整成最小堆
    29  
    30  ### 堆的使用场景
    31  
    32  - 构建优先队列
    33  
    34  - 支持堆排序
    35  
    36  - 快速找出一个集合中的最小值(或者最大值)
    37  
    38  
    39  ### List 双链表
    40  
    41  List 提供了对链表的实现,  list.go 中提供两个元素, List 和 Element , 其中 List 实现了一个双向链表, Element表示链表中元素的结构
    42  
    43  > <font color='red'>注意: container/list默认不是线程安全的,要保证数据安全,那么可以使用Lock锁解决。</font>
    44  
    45  ### 结构定义 
    46  
    47  ```go 
    48  type Element struct {
    49  	// Next and previous pointers in the doubly-linked list of elements.
    50  	// To simplify the implementation, internally a list l is implemented
    51  	// as a ring, such that &l.root is both the next element of the last
    52  	// list element (l.Back()) and the previous element of the first list
    53  	// element (l.Front()).
    54  	next, prev *Element // 上一个和下一个元素的指针
    55  
    56  	// The list to which this element belongs.
    57  	list *List // 元素所在的链表
    58  
    59  	// The value stored with this element.
    60  	Value interface{} // 元素值
    61  }
    62  
    63  type List struct {
    64  	// root 链表的根元素, 用来判断链表是否已经到了链尾了
    65  	root Element // sentinel list element, only &root, root.prev, and root.next are used
    66  	// 链表长度
    67  	len int // current list length excluding (this) sentinel element
    68  }
    69  ```
    70  
    71  ### 方法集
    72  
    73  ```go 
    74  type Element
    75      func (e *Element) Next() *Element                                   // 返回该元素的下一个元素,如果没有下一个元素则返回 nil
    76      func (e *Element) Prev() *Element                                   // 返回该元素的前一个元素,如果没有前一个元素则返回nil
    77  
    78  type List     
    79      // New, Init, 读取第一个, 最后一个元素, 获取链表长度, 删除一个元素                           
    80      func New() *List                                                    // 返回一个初始化的list
    81      func (l *List) Init() *List                                         // list l 初始化或者清除 list l
    82      func (l *List) Back() *Element                                      // 获取list l的最后一个元素
    83      func (l *List) Front() *Element                                     // 获取list l的最后一个元素
    84      func (l *List) Len() int                                            // 获取 list l 的长度
    85      func (l *List) Remove(e *Element) interface{}                       // 如果元素 e 属于list l,将其从 list 中删除,并返回元素 e 的值
    86  
    87      // 插入一个元素, 插入到链表头部或者末尾 
    88      func (l *List) PushFront(v interface{}) *Element                    // 在 list l 的首部插入值为 v 的元素,并返回该元素              
    89      func (l *List) PushBack(v interface{}) *Element                     // 在 list l 的末尾插入值为 v 的元素,并返回该元素              
    90  
    91      // 在指定元素之前/之后插入一个新值v的元素
    92      func (l *List) InsertAfter(v interface{}, mark *Element) *Element   // 在 list l 中元素 mark 之后插入一个值为 v 的元素,并返回该元素,如果 mark 不是list中元素,则 list 不改变
    93      func (l *List) InsertBefore(v interface{}, mark *Element) *Element  // 在 list l 中元素 mark 之前插入一个值为 v 的元素,并返回该元素,如果 mark 不是list中元素,则 list 不改变
    94      
    95      // 移动一个已经存在的元素到指定元素之前/之后
    96      func (l *List) MoveAfter(e, mark *Element)                          // 将元素 e 移动到元素 mark 之后,如果元素e 或者 mark 不属于 list l,或者 e==mark,则 list l 不改变
    97      func (l *List) MoveBefore(e, mark *Element)                         // 将元素 e 移动到元素 mark 之前,如果元素e 或者 mark 不属于 list l,或者 e==mark,则 list l 不改变
    98      
    99      // 移动一个存在的元素到链表头部/末尾
   100      func (l *List) MoveToBack(e *Element)                               // 将元素 e 移动到 list l 的末尾,如果 e 不属于list l,则list不改变             
   101      func (l *List) MoveToFront(e *Element)                              // 将元素 e 移动到 list l 的首部,如果 e 不属于list l,则list不改变             
   102      
   103      // 在链表头部/末尾 插入另外一个链表
   104      func (l *List) PushBackList(other *List)                            // 在 list l 的尾部插入另外一个 list,其中l 和 other 可以相等               
   105      func (l *List) PushFrontList(other *List)                           // 在 list l 的首部插入另外一个 list,其中 l 和 other 可以相等              
   106  ```
   107  
   108  ### var l list.List 声明的变量 l 可以直接用吗? 值将会是什么呢?
   109  
   110  - 可以的。这被称为 开箱即用。 这种通过语句 var l list.List 声明的链表 l 可以直接使用的原因就是在于它的 延迟初始化 机制。
   111  
   112  - l将会是一个长度为 0 的链表,这个链表持有的根元素也将会是一个空壳,其中只会包含缺省的内容。
   113  
   114  
   115  ### Ring  循环链表, 环 
   116  
   117  container/ring 包中的 Ring 类型实现的是一个循环链表,俗称的环。其实 List 在内部就是一个循环链表。它的根元素永远不会持有任何实际的元素值,而该元素的存在就是为了连接这个循环链表的首尾两端。
   118  
   119  所以,也可以说:List 的零值是一个只包含了根元素,但不包含任何实际元素值的空链表。那么,既然 Ring 和 List 的本质上都是循环链表,它们到底有什么不同呢?
   120  
   121  Ring 和 List 的不同有以下几种:
   122  
   123  - Ring 类型的数据结构仅由它自身即可代表,而 List 类型则需要由它以及 Element 类型联合表示。这是表示方式上的不同,也是结构复杂度上的不同。
   124  
   125  - 一个 Ring 类型的值严格来讲,只代表了其所属的循环链表中的一个元素,而一个 List 类型的值则代表了一个完整的链表。这是表示维度上的不同。
   126  
   127  - 在创建并初始化一个 Ring 值得时候,我们可以指定它包含的元素数量,但是对于一个 List 值来说却不能这样做(也没必要这样做)。循环链表一旦被创建,其长度是不可变的。这是两个代码包中 New 函数在功能上的不同,也是两个类型在初始化值方面的第一个不同
   128  
   129  - 仅通过 var r ring.Ring 语句声明的 r 将会是一个长度为 1 的循环链表,而 List 类型的零值则是一个长度为 0 的链表。别忘了,List 中的根元素不会持有实际元素的值,因此计算长度时不会包含它。这是两个类型在初始化值方面的第二个不同。
   130  
   131  - Ring 值得 Len 方法的算法复杂度是 O(N) 的,而 List 值得 Len 方法的算法复杂度是 O(1)的。这是两者在性能方面最显而易见的差别。
   132  
   133  ### 方法集
   134  
   135  ```go
   136  type Ring struct {
   137  	next, prev *Ring // 前后环指针
   138  	// 值,这个值在ring包中不会被处理
   139  	Value interface{} // for use by client; untouched by this library
   140  }
   141  
   142  
   143  type Ring
   144      func New(n int) *Ring               // 用于创建一个新的 Ring, 接收一个整形参数,用于初始化 Ring 的长度  
   145      func (r *Ring) Len() int            // 环长度
   146      
   147      func (r *Ring) Next() *Ring         // 返回当前元素的下个元素
   148      func (r *Ring) Prev() *Ring         // 返回当前元素的上个元素
   149      func (r *Ring) Move(n int) *Ring    // 指针从当前元素开始向后移动或者向前(n 可以为负数)
   150  
   151      // Link & Unlink 组合起来可以对多个链表进行管理
   152      func (r *Ring) Link(s *Ring) *Ring  // 将两个 ring 连接到一起 (r 不能为空)
   153      func (r *Ring) Unlink(n int) *Ring  // 从当前元素开始,删除 n 个元素
   154  
   155      func (r *Ring) Do(f func(interface{}))  // Do 会依次将每个节点的 Value 当作参数调用这个函数 f, 实际上这是策略方法的引用,通过传递不同的函数以在同一个 ring 上实现多种不同的操作。
   156  ```
   157  
   158  ### 遍历ring 
   159  
   160  ```go 
   161  // 方式一
   162  p := ring.Next()
   163  // do something with the first element
   164  
   165  for p != ring {
   166      // do something with current element
   167      p = p.Next()
   168  }
   169  
   170  // 方式二 
   171  ring.Do(func(i interface{}){
   172      // do something with current element 
   173  })
   174  
   175  // 方式三,四,五 ... 参考ring包提供的方式 
   176  ```
   177  
   178  可见通过ring.Do() 可以非常方便的将一组参数/规则 应用到函数中;
   179  
   180  ring 包提供了很多使用示例可供参考
   181