Is there a queue implementation?

后端 未结 14 1052
时光取名叫无心
时光取名叫无心 2020-12-23 02:14

Can anyone suggest Go container for simple and fast FIF/queue, Go has 3 different containers: heap, list and vector. Which one is more

相关标签:
14条回答
  • 2020-12-23 02:39

    Either vector or list should work, but vector is probably the way to go. I say this because vector will probably allocate less often than list and garbage collection (in the current Go implementation) is fairly expensive. In a small program it probably won't matter, though.

    0 讨论(0)
  • 2020-12-23 02:39

    In fact, if what you want is a basic and easy to use fifo queue, slice provides all you need.

    queue := make([]int, 0)
    // Push to the queue
    queue = append(queue, 1)
    // Top (just get next element, don't remove it)
    x = queue[0]
    // Discard top element
    queue = queue[1:]
    // Is empty ?
    if len(queue) == 0 {
        fmt.Println("Queue is empty !")
    }
    

    Of course, we suppose that we can trust the inner implementation of append and slicing so that it avoid useless resize and reallocation. For basic usage, this is perfectly sufficient.

    0 讨论(0)
  • 2020-12-23 02:42

    I also implement the queue from slice as above. However, It's not thread-safe. So I decided to add a lock (mutex lock) to guarantee thread-safe.

    package queue
    
    import (
      "sync"
    )
    
    type Queue struct {
      lock *sync.Mutex
      Values []int
    }
    
    func Init() Queue {
      return Queue{&sync.Mutex{}, make([]int, 0)}
    }
    
    func (q *Queue) Enqueue(x int) {
      for {
        q.lock.Lock()
        q.Values = append(q.Values, x)
        q.lock.Unlock()
        return
      }
    }
    
    func (q *Queue) Dequeue() *int {
      for {
        if (len(q.Values) > 0) {
          q.lock.Lock()
          x := q.Values[0]
          q.Values = q.Values[1:]
          q.lock.Unlock()
          return &x
        }
        return nil
      }
      return nil
    }
    

    You can check my solution on github here simple queue

    0 讨论(0)
  • 2020-12-23 02:43
    type Queue struct {
        slice []int
        len   int
    }
    func newq() Queue {
        q := Queue{}
        q.slice = make([]int, 0)
        q.len = 0
        return q
    }
    func (q *Queue) Add(v int) {
        q.slice = append(q.slice, v)
        q.len++
    }
    
    func (q *Queue) PopLeft() int {
        a := q.slice[0]
        q.slice = q.slice[1:]
        q.len--
        return a
    }
    func (q *Queue) Pop() int {
        a := q.slice[q.len-1]
        q.slice = q.slice[:q.len-1]
        q.len--
        return a
    }
    
    

    For your basic need the code above would do

    0 讨论(0)
  • 2020-12-23 02:49

    Double stack implementation:

    O(1) Enqueue and Dequeue and uses slices (which tends to be better for cache misses).

    type Queue struct{
        enqueue, dequeue Stack
    }
    
    func (q *Queue) Enqueue(n *Thing){
        q.enqueue.Push(n)
    }
    
    func (q *Queue) Dequeue()(*Thing, bool){
        v, ok := q.dequeue.Pop()
        if ok{
            return v, true
        }
    
        for {
            v, ok := d.enqueue.Pop()
            if !ok{
                break
            }
    
            d.dequeue.Push(v)
        }
    
        return d.dequeue.Pop()
    }
    
    type Stack struct{
        v []*Thing
    }
    
    func (s *Stack)Push(n *Thing){
        s.v=append(s.v, n)
    }
    
    func (s *Stack) Pop()(*Thing, bool){
        if len(s.v) == 0 {
            return nil, false
        }
    
        lastIdx := len(s.v)-1
        v := s.v[lastIdx]
        s.v=s.v[:lastIdx]
        return v, true
    }
    
    0 讨论(0)
  • 2020-12-23 02:51

    I implemented a queue that will expand the underlying buffer automatically:

    package types
    
    // Note: this queue does not shrink the underlying buffer.                                                                                                               
    type queue struct {
            buf  [][4]int // change to the element data type that you need                                                                                                   
            head int
            tail int
    }
    
    func (q *queue) extend(need int) {
            if need-(len(q.buf)-q.head) > 0 {
                    if need-len(q.buf) <= 0 {
                            copy(q.buf, q.buf[q.head:q.tail])
                q.tail = q.tail - q.head
                            q.head = 0
                            return
                    }
    
                    newSize := len(q.buf) * 2
                    if newSize == 0 {
                        newSize = 100
                }
                    newBuf := make([][4]int, newSize)
                    copy(newBuf, q.buf[q.head:q.tail])
                    q.buf = newBuf
            q.tail = q.tail - q.head
                    q.head = 0
            }
    }
    
    func (q *queue) push(p [4]int) {
            q.extend(q.tail + 1)
            q.buf[q.tail] = p
            q.tail++
    }
    
    func (q *queue) pop() [4]int {
            r := q.buf[q.head]
            q.head++
            return r
    }
    
    func (q *queue) size() int {
            return q.tail - q.head
    }
    
    
    // put the following into queue_test.go
    package types
    
    import (
            "testing"
    
            "github.com/stretchr/testify/assert"
    )
    
    func TestQueue(t *testing.T) {
            const total = 1000
            q := &queue{}
            for i := 0; i < total; i++ {
                    q.push([4]int{i, i, i, i})
                    assert.Equal(t, i+1, q.size())
            }
    
        for i := 0; i < total; i++ {
                    v := q.pop()
                    assert.Equal(t, [4]int{i, i, i, i}, v)
                    assert.Equal(t, total-1-i, q.size())
            }
    }
    
    0 讨论(0)
提交回复
热议问题