我的优先队列的Pop方法有什么问题?

huangapple go评论76阅读模式
英文:

What's wrong with my Priority Queue's Pop method?

问题

根据Rob Pike的负载均衡器演示,我实现了自己的优先队列,但我的Pop方法不正确,有人能告诉我错在哪里吗?

package main

import (
    "fmt"
    "container/heap"
)

type ClassRecord struct {
    name  string
    grade int
}

type RecordHeap []*ClassRecord

func (p RecordHeap) Len() int { return len(p) }

func (p RecordHeap) Less(i, j int) bool {
    return p[i].grade < p[j].grade
}

func (p *RecordHeap) Swap(i, j int) {
    a := *p
    a[i], a[j] = a[j], a[i]
}

func (p *RecordHeap) Push(x interface{}) {
    a := *p
    n := len(a)
    a = a[0 : n+1]
    r := x.(*ClassRecord)
    a[n] = r
    *p = a
}

func (p *RecordHeap) Pop() interface{} {
    a := *p
    *p = a[0 : len(a)-1]
    r := a[len(a)-1]
    return r
}

func main() {
    a := make([]ClassRecord, 6)
    a[0] = ClassRecord{"John", 80}
    a[1] = ClassRecord{"Dan", 85}
    a[2] = ClassRecord{"Aron", 90}
    a[3] = ClassRecord{"Mark", 65}
    a[4] = ClassRecord{"Rob", 99}
    a[5] = ClassRecord{"Brian", 78}
    h := make(RecordHeap, 0, 100)
    for _, c := range a {
        fmt.Println(c)
        heap.Push(&h, &c)
        fmt.Println("Push: heap has", h.Len(), "items")
    }
    for i, x := 0, heap.Pop(&h).(*ClassRecord); i < 10 && x != nil; i++ {
        fmt.Println("Pop: heap has", h.Len(), "items")
        fmt.Println(*x)
    }
}

**编辑:**除了cthomo06指出的方法之外,另一种修复方法是创建一个指针数组,如下所示,

a := make([]*ClassRecord, 6)
a[0] = &ClassRecord{"John", 80}
a[1] = &ClassRecord{"Dan", 85}
......
英文:

Based on Rob Pike's load balancer demo, I implemented my own priority queue, but my Pop method is not right, can anyone tell me what's wrong?

package main

import (
    &quot;fmt&quot;
    &quot;container/heap&quot;
)

type ClassRecord struct {
    name  string
    grade int
}

type RecordHeap []*ClassRecord

func (p RecordHeap) Len() int { return len(p) }

func (p RecordHeap) Less(i, j int) bool {
    return p[i].grade &lt; p[j].grade
}

func (p *RecordHeap) Swap(i, j int) {
    a := *p
    a[i], a[j] = a[j], a[i]
}

func (p *RecordHeap) Push(x interface{}) {
    a := *p
    n := len(a)
    a = a[0 : n+1]
    r := x.(*ClassRecord)
    a[n] = r
    *p = a
}

func (p *RecordHeap) Pop() interface{} {
    a := *p
    *p = a[0 : len(a)-1]
    r := a[len(a)-1]
    return r
}

func main() {
    a := make([]ClassRecord, 6)
    a[0] = ClassRecord{&quot;John&quot;, 80}
    a[1] = ClassRecord{&quot;Dan&quot;, 85}
    a[2] = ClassRecord{&quot;Aron&quot;, 90}
    a[3] = ClassRecord{&quot;Mark&quot;, 65}
    a[4] = ClassRecord{&quot;Rob&quot;, 99}
    a[5] = ClassRecord{&quot;Brian&quot;, 78}
    h := make(RecordHeap, 0, 100)
    for _, c := range a {
        fmt.Println(c)
        heap.Push(&amp;h, &amp;c)
        fmt.Println(&quot;Push: heap has&quot;, h.Len(), &quot;items&quot;)
    }
    for i, x := 0, heap.Pop(&amp;h).(*ClassRecord); i &lt; 10 &amp;&amp; x != nil; i++ {
        fmt.Println(&quot;Pop: heap has&quot;, h.Len(), &quot;items&quot;)
        fmt.Println(*x)
    }
}

EDIT: besides the way cthom06 pointed out, another way to fix this is to create a pointer array as follows,

a := make([]*ClassRecord, 6)
a[0] = &amp;ClassRecord{&quot;John&quot;, 80}
a[1] = &amp;ClassRecord{&quot;Dan&quot;, 85}
......

答案1

得分: 1

编辑:

哦,我应该立刻看到这个问题。

heap.Push(&h, &c)

你推送了c的地址,在每次迭代range时都会被重用。堆中的每个记录都是指向内存中相同区域的指针,最终会变成Brian。我不确定这是否是预期行为还是编译器的错误,但是

t := c
heap.Push(&h, &t)

可以解决这个问题。

另外:你的for循环有问题。

for h.Len() > 0 {
    x := heap.Pop(&h...

应该修复它。

英文:

EDIT:

Oh I should've seen this right away.

heap.Push(&amp;h, &amp;c)

You push the address of c, which gets reused on each iteration of range. Every record in the heap is a pointer to the same area in memory, which ends up being Brian. I'm not sure if this is intended behavior or a compiler bug, but

t := c
heap.Push(&amp;h, &amp;t)

works around it.

Also: Your for loop is wrong.

for h.Len() &gt; 0 {
    x := heap.Pop(&amp;h...

should fix it.

huangapple
  • 本文由 发表于 2010年8月12日 23:48:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/3469513.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定