优先队列和堆

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

Priority queue and heap

问题

我正在尝试根据文档中提供的示例实现一个基于优先级队列的代码。文档链接:priorityQueue

简要来说,代码如下(未包含全部内容):

package pq

type Item struct {
	container interface{}
	priority  int
	index     int
}

type PriorityQueue []*Item

func NewItem(value interface{}, prio int) *Item {
	return &Item{container: value, priority: prio}
}

func (pq PriorityQueue) Len() int {
	return len(pq)
}

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].priority > pq[j].priority
}

func (pq *PriorityQueue) Swap(i, j int) {
	(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
	(*pq)[i].index = i
	(*pq)[j].index = j
}

func (pq PriorityQueue) Push(x interface{}) {
	fmt.Printf("adr: %p\n", &pq)
	n := len(pq)
	item := x.(*Item)
	item.index = n
	pq = append(pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	itm := old[n-1]
	itm.index = -1
	*pq = old[0 : n-1]
	return itm.container
}

main.go 文件:

func main() {
	q := pq.PriorityQueue{}
	heap.Init(q)
	fmt.Printf("\nAdr: %p\n", &q)
	q.Push(pq.NewItem("h", 2))

	for i := 0; i < 5; i++ {
		item := pq.NewItem("test", i*13%7)
		heap.Push(q, item)
	}

	for q.Len() > 0 {
		fmt.Println("Item: " + heap.Pop(q).(string))
	}
}

从代码中可以看出,与示例不同的是,我没有使用指针,因为这样做会导致编译错误,告诉我我的优先级队列没有正确实现接口。

这导致了以下问题:

heap.Push(q, item)

这个操作没有将 item 添加到队列中。

我尝试打印出队列的指针地址,发现它们显示的是不同的地址。这解释了为什么它不起作用,但是切片不应该是引用类型吗,和映射一样吗?

更具体地说,我该如何解决这个问题?

希望你能帮助我!

编辑:添加了完整的代码和错误信息:cannot use q (type pq.PriorityQueue) as type heap.Interface in function argument: pq.PriorityQueue does not implement heap.Interface (Pop method has pointer receiver)

英文:

I'm trying to implement a priority queue based on the example provided in the documentation.
Docs: priorityQueue

In short it looks like this (not everything is included):

    package pq

    type Item struct {
    	container interface{}
    	priority  int
    	index     int
    }
    
    type PriorityQueue []*Item
    
    func NewItem(value interface{}, prio int) *Item {
    	return &amp;Item {container: value, priority: prio}
    }

func (pq PriorityQueue) Len() int {
	return len(pq)
}

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].priority &gt; pq[j].priority
}

func (pq *PriorityQueue) Swap(i, j int) {
	(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
	(*pq)[i].index = i
	(*pq)[j].index = j
}
    
    func (pq PriorityQueue) Push(x interface{}) {
    	fmt.Printf(&quot;adr: %p\n&quot;, &amp;pq)
    	n := len(pq)
    	item := x.(*Item)
    	item.index = n
    	pq = append(pq, item)
    }

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	itm := old[n - 1]
	itm.index = -1
	*pq = old[0 : n-1]
	return itm.container
}

The main.go file:

func main() {
	q := pq.PriorityQueue{}
	heap.Init(q)
	fmt.Printf(&quot;\nAdr: %p\n&quot;, &amp;q)
	q.Push(pq.NewItem(&quot;h&quot;, 2))

	for i := 0; i &lt; 5; i++ {
		item := pq.NewItem(&quot;test&quot;, i * 13 % 7)
		heap.Push(q, item)
	}

	for q.Len() &gt; 0 {
		fmt.Println(&quot;Item: &quot; + heap.Pop(q).(string))
	}
}

As you can see when comparing to the example I do not use pointers since doing that will give me a compile error telling me that my priority queue does not implement the interface properly.

This leaves me with the following problem when I do:

heap.Push(q, item)

that the item is not appended to the queue.

I've tried to write out the queues pointer address and it shows different addresses. This explains why it does not work, but souldn't slices not be reference types a long with maps?

And more specificly: How do i solve my problem?

Hope you can help!

Edit: Added full code and error: cannot use q (type pq.PriorityQueue) as type heap.Interface in function argument:
pq.PriorityQueue does not implement heap.Interface (Pop method has pointer receiver)

答案1

得分: 2

如示例代码所示,Push 方法必须具有指针接收器。

诀窍在于,对 heap.XXX 函数的所有调用都要求将堆作为指针传递(例如:heap.Init(&amp;pq))。但是在你发布的代码中并非如此。以下是你的代码的工作版本。你可以在 Go playground 上运行它。

请注意,在此代码中,我明确将队列初始化为指针:q := new(PriorityQueue)。并且这是我传递给所有 heap 函数的内容。

这里的混淆主要是因为你实际上正在实现两个接口。
heap.Interfacesort.Interface(后者是前者类型定义的一部分)。但是,sort 接口对于非指针接收器是可以的,而另一个接口则不行。

package main

import "fmt"
import "container/heap"

func main() {
    q := new(PriorityQueue)

    heap.Init(q)

    fmt.Printf("\nAdr: %p\n", &q)
    q.Push(NewItem("h", 2))

    for i := 0; i < 5; i++ {
        heap.Push(q, NewItem("test", i*13%7))
    }

    for q.Len() > 0 {
        fmt.Println("Item: " + heap.Pop(q).(string))
    }
}

type Item struct {
    container interface{}
    priority  int
    index     int
}

type PriorityQueue []*Item

func NewItem(value interface{}, prio int) *Item {
    return &Item{container: value, priority: prio}
}

func (pq PriorityQueue) Len() int {
    return len(pq)
}

func (pq PriorityQueue) Less(i, j int) bool {
    return pq[i].priority > pq[j].priority
}

func (pq PriorityQueue) Swap(i, j int) {
    pq[i], pq[j] = pq[j], pq[i]
    pq[i].index = i
    pq[j].index = j
}

func (pq *PriorityQueue) Push(x interface{}) {
    fmt.Printf("adr: %p\n", pq)
    n := len(*pq)
    item := x.(*Item)
    item.index = n
    *pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
    old := *pq
    n := len(old)
    itm := old[n-1]
    itm.index = -1
    *pq = old[0 : n-1]
    return itm.container
}
英文:

As the example code shows, the Push method must have a pointer receiver.

The trick is that all the calls to heap.XXX functions, require that you pass your heap in as a pointer (e.g.: heap.Init(&amp;pq)). This is not the case in the code you posted. Here is a working version of your code. You can run it on the Go playground.

Note that in this code, I explicitly initialize the queue as a pointer: q := new(PriorityQueue). And this is what I pass in to all the heap functions.

The confusion here arises mostly because you are essentially implementing 2 interfaces.
The heap.Interface and the sort.Interface (The latter is part of the prior's type definition). But the sort interface is fine with non-pointer receivers, while the other one is not.

package main
import &quot;fmt&quot;
import &quot;container/heap&quot;
func main() {
q := new(PriorityQueue)
heap.Init(q)
fmt.Printf(&quot;\nAdr: %p\n&quot;, &amp;q)
q.Push(NewItem(&quot;h&quot;, 2))
for i := 0; i &lt; 5; i++ {
heap.Push(q, NewItem(&quot;test&quot;, i*13%7))
}
for q.Len() &gt; 0 {
fmt.Println(&quot;Item: &quot; + heap.Pop(q).(string))
}
}
type Item struct {
container interface{}
priority  int
index     int
}
type PriorityQueue []*Item
func NewItem(value interface{}, prio int) *Item {
return &amp;Item{container: value, priority: prio}
}
func (pq PriorityQueue) Len() int {
return len(pq)
}
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].priority &gt; pq[j].priority
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = i
pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
fmt.Printf(&quot;adr: %p\n&quot;, pq)
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
itm := old[n-1]
itm.index = -1
*pq = old[0 : n-1]
return itm.container
}

huangapple
  • 本文由 发表于 2014年3月21日 03:19:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/22543025.html
匿名

发表评论

匿名网友

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

确定