美文网首页
golang中用slice实现queue

golang中用slice实现queue

作者: 劫客轮蹲 | 来源:发表于2019-12-09 18:22 被阅读0次

实现一

最直观的实现,用一个slice。

type Queue struct {
  s []*valueType
}

func (q *Queue) pushBack(v *valueType) {
  s = append(s, v)
}

func (q *Queue) popFront() *valueType {
  if len(s) == 0 {
    return nil
  }
  
  v := s[0]
  s[0] = nil
  s = s[1:]
  return v
}

这有个问题,Queue中的slice所占的内存并不会随着popFront操作而释放,已经出队的元素所占的内存仍在slice底层的数组中保留,直到slice扩容才会释放原来的内存,这样导致频繁的申请和释放内存。

实现二

用两个slice构造一个queue,在go net.http.transport包中有个wantConnQueue的实现,看注释是参考了Okasaki's purely functional queue.

// A wantConnQueue is a queue of wantConns.
type wantConnQueue struct {
    // This is a queue, not a deque.
    // It is split into two stages - head[headPos:] and tail.
    // popFront is trivial (headPos++) on the first stage, and
    // pushBack is trivial (append) on the second stage.
    // If the first stage is empty, popFront can swap the
    // first and second stages to remedy the situation.
    //
    // This two-stage split is analogous to the use of two lists
    // in Okasaki's purely functional queue but without the
    // overhead of reversing the list when swapping stages.
    head    []*wantConn
    headPos int
    tail    []*wantConn
}

// len returns the number of items in the queue.
func (q *wantConnQueue) len() int {
    return len(q.head) - q.headPos + len(q.tail)
}

// pushBack adds w to the back of the queue.
func (q *wantConnQueue) pushBack(w *wantConn) {
    q.tail = append(q.tail, w)
}

// popFront removes and returns the wantConn at the front of the queue.
func (q *wantConnQueue) popFront() *wantConn {
    if q.headPos >= len(q.head) {
        if len(q.tail) == 0 {
            return nil
        }
        // Pick up tail as new head, clear tail.
        q.head, q.headPos, q.tail = q.tail, 0, q.head[:0]
    }
    w := q.head[q.headPos]
    q.head[q.headPos] = nil
    q.headPos++
    return w
}

// peekFront returns the wantConn at the front of the queue without removing it.
func (q *wantConnQueue) peekFront() *wantConn {
    if q.headPos < len(q.head) {
        return q.head[q.headPos]
    }
    if len(q.tail) > 0 {
        return q.tail[0]
    }
    return nil
}

// cleanFront pops any wantConns that are no longer waiting from the head of the
// queue, reporting whether any were popped.
func (q *wantConnQueue) cleanFront() (cleaned bool) {
    for {
        w := q.peekFront()
        if w == nil || w.waiting() {
            return cleaned
        }
        q.popFront()
        cleaned = true
    }
}

入队的时候,append到tail中。出队的时候,从head[headPos]中取第一个元素,如果head空了,就交换head和tail。这样head slice为空的时候,与tail slice交换,底层的数组空间可以重用,从而节省内存空间。

reference

相关文章

  • golang中用slice实现queue

    实现一 最直观的实现,用一个slice。 这有个问题,Queue中的slice所占的内存并不会随着popFront...

  • golang 切片小结

    golang slice

  • slice切片做函数参数

    首先要明确一点:slice作为函数参数是值传递. 再来分析一下golang中的切片slice底层的实现细节...

  • golang slice

    关于golang slice有很多大神写了很多文章,阐述了slice的底层实现和使用中注意点.这篇文章是我参考ht...

  • golang slice的误解

    slice的介绍: 在golang的官方文档中,我们发现golang除了有array的数据还有一个slice,而a...

  • 剖析golang slice的实现

    本文基于golang 1.10版本分析。 slice 结构 slice实际就是一个struct,在runtime/...

  • Golang slice 的底层实现

    首先我们来看段代码的输出 输出的结果是 append的值5并没有输出,那么究竟是s0并不等价于s[0],还是有其他...

  • golang中slice底层实现

    什么是切片 切片就是我们经常所说的动态数组,可以灵活的增加和减少切片内的元素。常见的切片操作有:reslice、a...

  • Golang之数组和切片

    引用 数组、字符串和切片 Go数组中的索引问题 深入解析 Go 中 Slice 底层实现 Golang 入门 : ...

  • Learn Golang in 21 Days - Day 10

    Learn Golang in 21 Days - Day 10 知识点 切片Slice Slice是对数组的抽象...

网友评论

      本文标题:golang中用slice实现queue

      本文链接:https://www.haomeiwen.com/subject/htdigctx.html