Go中container/ring包


Ring是一种循环链表结构 没有头尾
从任意一个节点出发都可以遍历整个链
其定义如下 Value表示当前节点的值
type Ring struct {
        Value interface{}
}
类型方法New
Ring.New用于创建一个新的Ring 接收一个整形参数 用于初始化Ring的长度 其方法定义如下:
func New(n int) *Ring
Next & Prev
作为一个链表 最重要的操作进行遍历 可以通过Next和Prev方法获取当前节点的上一个节点和下一个节点 方法定义如下:
func (r *Ring) Next() *Ring
func (r *Ring) Prev() *Ring
通过这两个方法可以对一个ring进行遍历
首先保存当前节点 然后依次访问下一个节点 直到回到起始节点 代码实现如下
p := ring.Next()//  do something with first element
for p != ring {  // do something with current element
    p = p.Next()
}
Link & Unlink
Link将两个ring连接到一起 而Unlink将一个ring拆分为两个 移除n个元素并组成一个新的ring 这两个操作组合起来可以对多个链表进行管理 方法声明
func (r *Ring) Link(s *Ring) *Ring
func (r *Ring) Unlink(n int) *Ring
Do 前面通过Next方法对ring进行了遍历 由于这类操作的广泛存在 所以Ring包中还提供了一个额外的方法Do 方法接收一个函数作为参数 方法声明
func (r *Ring) Do(f func(interface{}))
在调用Ring.Do时 会依次将每个节点的Value当做参数调用这个函数 实际上这是策略方法的应用 通过传递不同的函数 可在同个ring上多种不同的操作
简单的遍历打印程序
package main
import (
    "container/ring"
    "fmt"
)
func main() {
    r := ring.New(10)
    for i := 0; i < 10; i++ {
            r.Value = i
            r = r.Next()
    }
    sum := SumInt{}
    r.Do(func(i interface{}) {
            fmt.Println(i)
    })
}
除了简单的无状态程序外 也可以通过结构体保存状态
例如下面是一个对ring上值求和的程序
package main
import (
    "container/ring"
    "fmt"
)
type SumInt struct {
    Value int
}
func (s *SumInt) add(i interface{}) {
    s.Value += i.(int)
}
func main() {
    r := ring.New(10)
    for i := 0; i < 10; i++ {
            r.Value = i
            r = r.Next()
    }
    sum := SumInt{}
    r.Do(sum.add)
    fmt.Println(sum.Value)
}
ring包实现 环形链表的操作
type Ring  //Ring类型代表环形链表的一个元素 同时也代表链表本身
环形链表没有头尾 指向环形链表任一元素的指针都可以作为整个环形链表看待
Ring零值是具有一个(Value字段为nil的)元素的链表
type Ring struct {
        Value interface{} // 供调用者使用 本包不会对该值进行操作
        // 包含未导出字段
}
func New(n int) *Ring //创建一个长度为n的环形链表
func (r *Ring) Do(f func(interface{}))  //对链表中任意元素执行f操作 若f改变了r 则该操作造成的后果是不可预期的
func (r *Ring) Len() int  //求环长度 返回环中元素数量
func (r *Ring) Link(s *Ring) *Ring  //Link连接r和s 并返回r原本的后继元素r.Next()
r不能为空
若r和s指向同一个环形链表 则会删除掉r和s之间的元素 删掉的元素构成一个子链表 返回指向该子链表的指针(r的原后继元素)
若没有删除元素 则仍然返回r的原后继元素 而不是nil
若r和s指向不同的链表 将创建一个单独的链表 将s指向的链表插入r后面 返回s原最后一个元素后面的元素(即r的原后继元素)
func (r *Ring) Unlink(n int) *Ring //删除链表中n % r.Len()个元素 从r.Next()开始删除
若n % r.Len() == 0 不修改r
返回删除的元素构成的链表 r不能为空
func (r *Ring) Move(n int) *Ring  //返回移动n个位置(n>=0向前移动 n<0向后移动)后的元素 r不能为空
func (r *Ring) Next() *Ring  //获取当前元素的下个元素
func (r *Ring) Prev() *Ring //获取当前元素的上个元素
用法
package main     
import (
    "container/ring"
    "fmt"
)     
func main() {
    RingFunc()     
}
func RingFunc() {
    r := ring.New(10) //初始长度10
    for i := 0; i < r.Len(); i++ {
        r.Value = i
        r = r.Next()
    }
    for i := 0; i < r.Len(); i++ {
        fmt.Println(r.Value)
        r = r.Next()
    }
    r = r.Move(6)
    fmt.Println(r.Value) //6
    r1 := r.Unlink(19)   //移除19%10=9个元素
    for i := 0; i < r1.Len(); i++ {
        fmt.Println(r1.Value)
        r1 = r1.Next()
    }
    fmt.Println(r.Len())  //10-9=1
    fmt.Println(r1.Len()) //9
}