新增优先队列

This commit is contained in:
boyce
2021-05-24 18:53:13 +08:00
parent 812c7a0717
commit 99d495dce4
3 changed files with 117 additions and 178 deletions

View File

@@ -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)
}

View File

@@ -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)
}
}

View File

@@ -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()
}
}