diff --git a/util/queue/priorityqueue.go b/util/queue/priorityqueue.go new file mode 100644 index 0000000..c07e725 --- /dev/null +++ b/util/queue/priorityqueue.go @@ -0,0 +1,82 @@ +package queue + +import "container/heap" + +// An Item is something we manage in a Priority queue. +type Item struct { + Value interface{} // The Value of the item; arbitrary. + Priority int // The Priority of the item in the queue. + // The Index is needed by update and is maintained by the heap.Interface methods. + Index int // The Index of the item in the heap. +} + +// A PriorityQueueSlice implements heap.Interface and holds Items. +type PriorityQueueSlice []*Item + +func (pq PriorityQueueSlice) Len() int { return len(pq) } + +func (pq PriorityQueueSlice) Less(i, j int) bool { + // We want Pop to give us the highest, not lowest, Priority so we use greater than here. + return pq[i].Priority < pq[j].Priority +} + +func (pq PriorityQueueSlice) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] + pq[i].Index = i + pq[j].Index = j +} + +func (pq *PriorityQueueSlice) Push(x interface{}) { + n := len(*pq) + item := x.(*Item) + item.Index = n + *pq = append(*pq, item) +} + +func (pq *PriorityQueueSlice) Pop() interface{} { + old := *pq + n := len(old) + item := old[n-1] + item.Index = -1 // for safety + *pq = old[0 : n-1] + return item +} + +// update modifies the Priority and Value of an Item in the queue. +func (pq *PriorityQueueSlice) Update(item *Item, value interface{}, priority int) { + item.Value = value + item.Priority = priority + heap.Fix(pq, item.Index) +} + +type PriorityQueue struct { + priorityQueueSlice PriorityQueueSlice +} + +//参数是数据大小 +func (pq *PriorityQueue) Init(initItemSliceNum int){ + pq.priorityQueueSlice = make(PriorityQueueSlice,0,initItemSliceNum) +} + +func (pq *PriorityQueue) Push(item *Item){ + heap.Push(&pq.priorityQueueSlice, item) +} + +func (pq *PriorityQueue) Pop() *Item { + if pq.Len() ==0 { + return nil + } + return heap.Pop(&pq.priorityQueueSlice).(*Item) +} + +func (pq *PriorityQueue) Len() int { + return len(pq.priorityQueueSlice) +} + +func (pq *PriorityQueue) Update(item *Item, value interface{}, priority int){ + pq.priorityQueueSlice.Update(item, value, priority) +} + +func (pq *PriorityQueue) Remove(item *Item){ + heap.Remove(&pq.priorityQueueSlice,item.Index) +} diff --git a/util/queue/priorityqueue_test.go b/util/queue/priorityqueue_test.go new file mode 100644 index 0000000..c73b046 --- /dev/null +++ b/util/queue/priorityqueue_test.go @@ -0,0 +1,35 @@ +package queue + +import "testing" + +func TestPriorityQueueSimple(t *testing.T) { + var queue PriorityQueue + queue.Init(100) + var item1,item2,item3,item4 Item + item1.Value = "xxxx1" + item1.Priority = 100 + + item2.Value = "xxxx2" + item2.Priority = 99 + + item3.Value = "xxxx3" + item3.Priority = 85 + + item4.Value = "xxxx4" + item4.Priority = 10 + + queue.Push(&item1) + queue.Push(&item2) + queue.Push(&item3) + queue.Push(&item4) + + queue.Remove(&item2) + + for{ + item := queue.Pop() + if item == nil { + break + } + t.Log(item) + } +} diff --git a/util/queue/queue_test.go b/util/queue/queue_test.go deleted file mode 100644 index a875848..0000000 --- a/util/queue/queue_test.go +++ /dev/null @@ -1,178 +0,0 @@ -package queue - -import "testing" - -func TestQueueSimple(t *testing.T) { - q := New() - - for i := 0; i < minQueueLen; i++ { - q.Add(i) - } - for i := 0; i < minQueueLen; i++ { - if q.Peek().(int) != i { - t.Error("peek", i, "had value", q.Peek()) - } - x := q.Remove() - if x != i { - t.Error("remove", i, "had value", x) - } - } -} - -func TestQueueWrapping(t *testing.T) { - q := New() - - for i := 0; i < minQueueLen; i++ { - q.Add(i) - } - for i := 0; i < 3; i++ { - q.Remove() - q.Add(minQueueLen + i) - } - - for i := 0; i < minQueueLen; i++ { - if q.Peek().(int) != i+3 { - t.Error("peek", i, "had value", q.Peek()) - } - q.Remove() - } -} - -func TestQueueLength(t *testing.T) { - q := New() - - if q.Length() != 0 { - t.Error("empty queue length not 0") - } - - for i := 0; i < 1000; i++ { - q.Add(i) - if q.Length() != i+1 { - t.Error("adding: queue with", i, "elements has length", q.Length()) - } - } - for i := 0; i < 1000; i++ { - q.Remove() - if q.Length() != 1000-i-1 { - t.Error("removing: queue with", 1000-i-i, "elements has length", q.Length()) - } - } -} - -func TestQueueGet(t *testing.T) { - q := New() - - for i := 0; i < 1000; i++ { - q.Add(i) - for j := 0; j < q.Length(); j++ { - if q.Get(j).(int) != j { - t.Errorf("index %d doesn't contain %d", j, j) - } - } - } -} - -func TestQueueGetNegative(t *testing.T) { - q := New() - - for i := 0; i < 1000; i++ { - q.Add(i) - for j := 1; j <= q.Length(); j++ { - if q.Get(-j).(int) != q.Length()-j { - t.Errorf("index %d doesn't contain %d", -j, q.Length()-j) - } - } - } -} - -func TestQueueGetOutOfRangePanics(t *testing.T) { - q := New() - - q.Add(1) - q.Add(2) - q.Add(3) - - assertPanics(t, "should panic when negative index", func() { - q.Get(-4) - }) - - assertPanics(t, "should panic when index greater than length", func() { - q.Get(4) - }) -} - -func TestQueuePeekOutOfRangePanics(t *testing.T) { - q := New() - - assertPanics(t, "should panic when peeking empty queue", func() { - q.Peek() - }) - - q.Add(1) - q.Remove() - - assertPanics(t, "should panic when peeking emptied queue", func() { - q.Peek() - }) -} - -func TestQueueRemoveOutOfRangePanics(t *testing.T) { - q := New() - - assertPanics(t, "should panic when removing empty queue", func() { - q.Remove() - }) - - q.Add(1) - q.Remove() - - assertPanics(t, "should panic when removing emptied queue", func() { - q.Remove() - }) -} - -func assertPanics(t *testing.T, name string, f func()) { - defer func() { - if r := recover(); r == nil { - t.Errorf("%s: didn't panic as expected", name) - } - }() - - f() -} - -// General warning: Go's benchmark utility (go test -bench .) increases the number of -// iterations until the benchmarks take a reasonable amount of time to run; memory usage -// is *NOT* considered. On my machine, these benchmarks hit around ~1GB before they've had -// enough, but if you have less than that available and start swapping, then all bets are off. - -func BenchmarkQueueSerial(b *testing.B) { - q := New() - for i := 0; i < b.N; i++ { - q.Add(nil) - } - for i := 0; i < b.N; i++ { - q.Peek() - q.Remove() - } -} - -func BenchmarkQueueGet(b *testing.B) { - q := New() - for i := 0; i < b.N; i++ { - q.Add(i) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - q.Get(i) - } -} - -func BenchmarkQueueTickTock(b *testing.B) { - q := New() - for i := 0; i < b.N; i++ { - q.Add(nil) - q.Peek() - q.Remove() - } -}