mirror of
https://github.com/duanhf2012/origin.git
synced 2026-02-03 22:45:13 +08:00
新增优先队列
This commit is contained in:
82
util/queue/priorityqueue.go
Normal file
82
util/queue/priorityqueue.go
Normal 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)
|
||||
}
|
||||
35
util/queue/priorityqueue_test.go
Normal file
35
util/queue/priorityqueue_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user