From f61fd5d1be054c27eb682c6856b278babeba7438 Mon Sep 17 00:00:00 2001 From: orgin Date: Thu, 30 Jun 2022 09:50:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BE=AA=E7=8E=AF=E9=98=9F?= =?UTF-8?q?=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/queue/squeue.go | 159 +++++++++++++++++++++++++++++++++++ util/queue/syncqueue_test.go | 52 ++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 util/queue/squeue.go create mode 100644 util/queue/syncqueue_test.go diff --git a/util/queue/squeue.go b/util/queue/squeue.go new file mode 100644 index 0000000..c99ebf1 --- /dev/null +++ b/util/queue/squeue.go @@ -0,0 +1,159 @@ +package queue + +import ( + "sync" +) + +/* + 这是一个循环队列 +*/ +type SQueue[ElementType any] struct { + elements []ElementType + head int + tail int + locker sync.RWMutex +} + +//游标,通过该游标获取数据 +type SCursor[ElementType any] struct { + pos int + squeue *SQueue[ElementType] +} + +func NewSQueue[ElementType any](maxElementNum int) *SQueue[ElementType]{ + queue := &SQueue[ElementType]{} + queue.elements = make([]ElementType,maxElementNum+1) + + return queue +} + +//游标移动到队首 +func (s *SCursor[ElementType]) First(){ + s.squeue.locker.RLock() + defer s.squeue.locker.RUnlock() + s.pos = s.squeue.head +} + +//从当前位置移动游标,注意如果在多协程读或者pop时,可能会导致游标失效 +func (s *SCursor[ElementType]) Next() (elem ElementType,ret bool){ + s.squeue.locker.RLock() + defer s.squeue.locker.RUnlock() + + if s.pos == s.squeue.tail { + return + } + + s.pos++ + s.pos = (s.pos)%(len(s.squeue.elements)) + return s.squeue.elements[s.pos],true +} + +//获取队列元数个数 +func (s *SQueue[ElementType]) Len() int { + s.locker.RLock() + defer s.locker.RUnlock() + + if s.head <= s.tail { + return s.head - s.tail + } + + //(len(s.elements)-1-s.head)+(s.tail+1) + return len(s.elements)-s.head+s.tail +} + +//获取游标,默认是队首 +func (s *SQueue[ElementType]) GetCursor() (cur SCursor[ElementType]){ + s.locker.RLock() + defer s.locker.RUnlock() + + cur.squeue = s + cur.pos = s.head + return +} + +//获取指定位置的游标 +func (s *SQueue[ElementType]) GetPosCursor(pos int) (cur SCursor[ElementType],ret bool){ + s.locker.RLock() + defer s.locker.RUnlock() + + if s.head < s.tail { + if pos<=s.head || pos>s.tail{ + return + } + + ret = true + cur.squeue = s + cur.pos = pos + return + } + + if pos >s.tail && pos <=s.head { + return + } + + cur.squeue = s + cur.pos = pos + return +} + +//从队首移除掉指定数量元素 +func (s *SQueue[ElementType]) RemoveElement(elementNum int) (removeNum int) { + s.locker.Lock() + defer s.locker.Unlock() + + for ;s.head == s.tail && removeNum >= elementNum;{ + removeNum++ + s.head++ + s.head = s.head%len(s.elements) + } + + return +} + +//从队首Pop元素 +func (s *SQueue[ElementType]) Pop() (elem ElementType,ret bool){ + s.locker.Lock() + defer s.locker.Unlock() + + if s.head == s.tail { + return + } + + s.head++ + s.head = s.head%len(s.elements) + return s.elements[s.head],true +} + +//从队尾Push数据 +func (s *SQueue[ElementType]) Push(elem ElementType) bool { + s.locker.Lock() + defer s.locker.Unlock() + + nextPos := (s.tail+1) % len(s.elements) + if nextPos == s.head { + //is full + return false + } + + s.tail = nextPos + s.elements[s.tail] = elem + return true +} + +//判断队列是否为空 +func (s *SQueue[ElementType]) IsEmpty() bool{ + s.locker.RLock() + defer s.locker.RUnlock() + + return s.head == s.tail +} + +//判断队列是否已满 +func (s *SQueue[ElementType]) IsFull() bool{ + s.locker.RLock() + defer s.locker.RUnlock() + + nextPos := (s.tail+1) % len(s.elements) + return nextPos == s.head +} + diff --git a/util/queue/syncqueue_test.go b/util/queue/syncqueue_test.go new file mode 100644 index 0000000..3e5efa9 --- /dev/null +++ b/util/queue/syncqueue_test.go @@ -0,0 +1,52 @@ +package queue + +import ( + "testing" +) + +func Test_Example(t *testing.T) { + //1.创建阶列 + queue := NewSQueue[int](5) + + //2.判断是否为空 + t.Log("is empty :", queue.IsEmpty()) + t.Log("is full :", queue.IsFull()) + + //3.游标使用 + cursor := queue.GetCursor() + cursor.First() + for { + elem, ret := cursor.Next() + if ret == false { + break + } + t.Log("elem:", elem) + } + + //4.push数据 + for i := 0; i < 6; i++ { + t.Log("push:", queue.Push(i)) + } + + t.Log("is empty :", queue.IsEmpty()) + t.Log("is full :", queue.IsFull()) + + //5.游标遍历 + cursor.First() + for { + elem, ret := cursor.Next() + if ret == false { + break + } + t.Log("elem:", elem) + } + + //pop数据所有 + for i := 0; i < 6; i++ { + elem, ret := queue.Pop() + t.Log("pop:", elem, "-", ret, " len:", queue.Len()) + } + + t.Log("is empty :", queue.IsEmpty()) + t.Log("is full :", queue.IsFull()) +}