从优先队列中删除元素

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

Remove element from the Priority queue

问题

// 这个示例演示了使用堆接口构建的优先队列。
package main

import (
"container/heap"
"fmt"
)

// Item 是我们在优先队列中管理的东西。
type Item struct {
value int // 项目的值;任意值。
priority int // 项目在队列中的优先级。
// 索引由 update 方法所需,并由 heap.Interface 方法维护。
index int // 项目在堆中的索引。
}

// PriorityQueue 实现了 heap.Interface 并保存 Item。
type PriorityQueue []*Item

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

func (pq PriorityQueue) Less(i, j int) bool {
// 我们希望 Pop 给我们最高的优先级,所以这里使用大于号。
return pq[i].value > pq[j].value
}

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

func (pq *PriorityQueue) Push(x interface{}) {
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}

func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
item.index = -1 // 为了安全起见
*pq = old[0 : n-1]
return item
}

// update 修改队列中项目的优先级和值。
func (pq *PriorityQueue) update(item *Item, value int, priority int) {
item.value = value
item.priority = priority
heap.Fix(pq, item.index)
}

func main() {
nums := []int{1, 3, 2, -3, 5, 3, 6, 7, 8, 9}
k := 3
result := maxSlidingWindow(nums, k)
fmt.Println("result", result)
}

func maxSlidingWindow(nums []int, k int) {

pq := make(PriorityQueue, len(nums))
res := []int{}

for i := 0; i < k; i++ {
	pq[i] = &Item{
		value:    nums[i],
		priority: nums[i],
		index:    i,
	}
	res = append(res, nums[i])
}
heap.Init(&pq)
peek := pq[0]
fmt.Println(peek.value) // 这是一个最大堆,给出最大的元素

temp := heap.Pop(&pq).(*Item)
fmt.Println("temp:", temp)

remove := heap.Remove(&pq, 0).(*Item)
// pq = slices.Delete(pq, 5)
fmt.Println("remove:", remove)

for i := 0; i < len(nums); i++ {

	// 从优先队列中删除所需的元素
	// 将下一个元素插入优先队列
	// 查看最高值

}

}

英文:
// This example demonstrates a priority queue built using the heap interface.
package main

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

// An Item is something we manage in a priority queue.
type Item struct {
	value    int // 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 PriorityQueue implements heap.Interface and holds Items.
type PriorityQueue []*Item

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

func (pq PriorityQueue) 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].value &gt; pq[j].value
}

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

func (pq *PriorityQueue) Push(x interface{}) {
	n := len(*pq)
	item := x.(*Item)
	item.index = n
	*pq = append(*pq, item)
}

func (pq *PriorityQueue) 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 *PriorityQueue) update(item *Item, value int, priority int) {
	item.value = value
	item.priority = priority
	heap.Fix(pq, item.index)
}

func main() {
	nums := []int{1, 3, 2, -3, 5, 3, 6, 7, 8, 9}
	k := 3
	result := maxSlidingWindow(nums, k)
	fmt.Println(&quot;result&quot;, result)
}

func maxSlidingWindow(nums []int, k int) {

	pq := make(PriorityQueue, len(nums))
	res := []int{}

	for i := 0; i &lt; k; i++ {
		pq[i] = &amp;Item{
			value:    nums[i],
			priority: nums[i],
			index:    i,
		}
		res = append(res, nums[i])
	}
	heap.Init(&amp;pq)
	peek := pq[0]
	fmt.Println(peek.value) // its a maxheap and gives the largest element

	temp := heap.Pop(&amp;pq).(*Item)
	fmt.Println(&quot;temp:&quot;, temp)

	remove := heap.Remove(&amp;pq, 0).(*Item)
	// pq = slices.Delete(pq, 5)
	fmt.Println(&quot;remove:&quot;, remove)
    
    for i:=0;i&lt;len(nums);i++{
    
     //remove the desired element from the priority Queue 
     // insert the next element in the Priority queue
     // peek the highest value 

     }

}

I am trying to print the maximum value in a sliding window. Putting the elements of window size, here k = 3 into the priority queue(Maxheap) and then peek the value.
"heap.Init(&pq)" will assign the index in pq based on the priority. Look for maxSlidingWindow function, the last for loop prints the max element for each window of size k. If you compare the indices in the pq and the nums array the indices will be different. And hence deleting the desired element from the priority queue seems almost impossible.

答案1

得分: 1

你的问题不够清楚。我假设你希望你的maxSlidingWindow函数的行为如下:

maxSlidingWindow([]int{1, 3, 2,-3, 5, 3, 6, 7, 8, 9}, 3)

  返回   -->     []int{3, 3, 5, 5, 6, 7, 8, 9}

为了实现这个功能,可以按照以下步骤进行操作:

  1. nums中取出前k个值,填充优先队列(priority queue)。

    你的代码将nums中的所有值都放入了队列,这似乎不像是一个滑动窗口的方法。我对你的问题是否理解正确有所怀疑。

  2. 从队列中取出最大值,将其添加到result中。

  3. 对于klen(Data) - 1i

    1. 从优先队列中删除nums[i-k]元素,并将nums[i]推入队列。

      你应该使用heap.Remove来删除一个元素。Go的heap.Fix提供了一种将删除和推入步骤结合起来的方法。

    2. 取修改后的优先队列的最大值,将其添加到result中。

此外,你的队列实现有一个错误:

func (pq PriorityQueue) Swap(i, j int) {
    pq[i], pq[j] = pq[j], pq[i]
    pq[i].index = j // 应该是:pq[i].index = i
    pq[j].index = i // 应该是:pq[j].index = j
}

从优先队列中删除元素

根据问题的标题,似乎你无法让这部分工作起来:

从优先队列中删除nums[i-k]元素,并将nums[i]推入队列

使用Go的heap,要修改一个元素(使用heap.Fix)或删除一个元素(使用heap.Remove),需要知道该元素的索引。为了获得相应的索引,至少有两种方法。

请注意,我们需要区分nums中元素的索引和队列中元素的索引。我将在以下代码中将前者称为i,后者称为j。我们知道要删除的元素的i,但由于heap会改变队列,我们需要找到j

遍历队列并找到元素

这种方法很简单。这种情况下,你可以简化PriorityQueue类型:

type PriorityQueue []int
// 我将跳过heap.Interface部分

func maxSlidingWindow(nums []int, k int) []int {
	pq := make(PriorityQueue, k)
	result := make([]int, 0, len(nums)-k+1)

	for i := 0; i < k; i++ {           // 1.
		pq[i] = nums[i]
	}

	heap.Init(&pq)

	result = append(result, pq[0])     // 2.

	for i := k; i < len(nums); i++ {
		for j, value := range pq {     // 3.1.
			if value == nums[i-k] {
				pq[j] = nums[i]        // 不是删除再推入
				heap.Fix(&pq, j)       // 使用heap.Fix修改内容
				break
			}
		}
		result = append(result, pq[0]) // 3.2.
	}
	return result
}

它可以正确处理重复值。

保持外部的i -> j映射

以下只是一种可能的方法,可能不太优雅。我使用CircularArray来保持我们的映射:

type CircularArray []int

func (a CircularArray) wrapped(index int) int {
	return index % len(a)
}

func (a CircularArray) Get(index int) int {
	return a[a.wrapped(index)]
}

func (a CircularArray) Set(index int, value int) {
	a[a.wrapped(index)] = value
}

func (a CircularArray) Swap(i, j int) {
	ii, jj := a.wrapped(i), a.wrapped(j)
	a[ii], a[jj] = a[jj], a[ii]
}
type PriorityQueue struct {
	Window           []int         // 队列
	IndicesOfIndices CircularArray // `i -> j`映射
}

// func (pq *PriorityQueue) Len() ...
func (pq *PriorityQueue) Push(x interface{}) {} // 不使用
func (pq *PriorityQueue) Pop() interface{} { return nil } // 不使用

func (pq *PriorityQueue) Less(a, b int) bool {
	return pq.Window[a] > pq.Window[b]
}

func (pq *PriorityQueue) Swap(a, b int) {
	pq.Window[a], pq.Window[b] = pq.Window[b], pq.Window[a]
	pq.IndicesOfIndices.Swap(a, b)
}

func maxSlidingWindow(nums []int, k int) []int {
	pq := PriorityQueue{
		Window:           make([]int, 0, k),
		IndicesOfIndices: make(CircularArray, k),
	}

	result := make([]int, 1, len(nums)-k+1)

	for i := 0; i < k; i++ {
		pq.PushWithIndex(nums[i], i)                          // 1.
	}

	heap.Init(&pq)

	result[0] = pq.Window[0]                                  // 2.

	for i := k; i < len(nums); i++ {
		result = append(result, pq.NextWithIndex(nums[i], i)) // 3.
	}

	return result
}

// 推入队列并设置`i -> j`映射
func (pq *PriorityQueue) PushWithIndex(value int, i int) {
	pq.IndicesOfIndices.Set(i, len(pq.Window))
	pq.Window = append(pq.Window, value)
}

// 更新队列并返回最大元素
func (pq *PriorityQueue) NextWithIndex(pushed int, i int) int {
	j := pq.IndicesOfIndices.Get(i) // 3.1.
	pq.Window[j] = pushed
	heap.Fix(pq, j)
	return pq.Window[0]             // 3.2.
}
英文:

Your question is not clear enough. I assume that you want your maxSlidingWindow to behave like this:

maxSlidingWindow([]int{1, 3, 2,-3, 5, 3, 6, 7, 8, 9}, 3)
returns   --&gt;     []int{3, 3, 5, 5, 6, 7, 8, 9}

To achieve this, one might do the following:

  1. Fill a priority queue with the first k values from nums.

    Your code is putting all values from nums into the queue, which does not seem like a moving window approach. And I do doubt if I misunderstand your question.

  2. Take the max value from the queue, append it to the result.

  3. For i from k to len(Data) - 1:

    1. Discard the nums[i-k] element from the priority queue, and push into the queue nums[i].

      You should use use heap.Remove to remove an element. Go's heap.Fix provides a way to combine the removing and pushing steps.

    2. Take the max value of the modified priority queue, append it to the result.

Also, your implementation of the queue has a bug:

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

Removing elements from priority queues

According to the title of the question, it seems you cannot get this part working:

> Discard the nums[i-k] element from the priority queue, and push into the queue nums[i]

Using Go's heap, to modify an item (with heap.Fix) or remove one (with heap.Remove, an index to that item is required. To get the corresponding index, there are at least two ways.

Note that we need to distinguish from the indices of elements in nums and the indices of elements in the queue. I am to refer to the former one as i in the following code and the latter, j. We know the i of the element we want to remove, but since heap changes the queue, we need to find j.

Loop through the queue and find the element

Simple enough. In this way, you may just simplify the PriorityQueue type:

type PriorityQueue []int
// I will skip the heap.Interface part

func maxSlidingWindow(nums []int, k int) []int {
	pq := make(PriorityQueue, k)
	result := make([]int, 0, len(nums)-k+1)

	for i := 0; i &lt; k; i++ {           // 1.
		pq[i] = nums[i]
	}

	heap.Init(&amp;pq)

	result = append(result, pq[0])     // 2.

	for i := k; i &lt; len(nums); i++ {
		for j, value := range pq {     // 3.1.
			if value == nums[i-k] {
				pq[j] = nums[i]        // Instead of removing then pushing
				heap.Fix(&amp;pq, j)       // We modify the content with heap.Fix
				break
			}
		}
		result = append(result, pq[0]) // 3.2.
	}
	return result
}

It handles duplicate values correctly.

Keep a external i -&gt; j mapping

Below is just a possible way doing it and may not be that elegant. I use a CircularArray to keep our mapping:

type CircularArray []int

func (a CircularArray) wrapped(index int) int {
	return index % len(a)
}

func (a CircularArray) Get(index int) int {
	return a[a.wrapped(index)]
}

func (a CircularArray) Set(index int, value int) {
	a[a.wrapped(index)] = value
}

func (a CircularArray) Swap(i, j int) {
	ii, jj := a.wrapped(i), a.wrapped(j)
	a[ii], a[jj] = a[jj], a[ii]
}
type PriorityQueue struct {
	Window           []int         // The queue
	IndicesOfIndices CircularArray // `i -&gt; j` mapping
}

// func (pq *PriorityQueue) Len() ...
func (pq *PriorityQueue) Push(x interface{}) {} // don&#39;t use
func (pq *PriorityQueue) Pop() interface{} { return nil } // don&#39;t use

func (pq *PriorityQueue) Less(a, b int) bool {
	return pq.Window[a] &gt; pq.Window[b]
}

func (pq *PriorityQueue) Swap(a, b int) {
	pq.Window[a], pq.Window[b] = pq.Window[b], pq.Window[a]
	pq.IndicesOfIndices.Swap(a, b)
}

func maxSlidingWindow(nums []int, k int) []int {
	pq := PriorityQueue{
		Window:           make([]int, 0, k),
		IndicesOfIndices: make(CircularArray, k),
	}

	result := make([]int, 1, len(nums)-k+1)

	for i := 0; i &lt; k; i++ {
		pq.PushWithIndex(nums[i], i)                          // 1.
	}

	heap.Init(&amp;pq)

	result[0] = pq.Window[0]                                  // 2.

	for i := k; i &lt; len(nums); i++ {
		result = append(result, pq.NextWithIndex(nums[i], i)) // 3.
	}

	return result
}

// Pushes into the queue and sets up the `i -&gt; j` mapping
func (pq *PriorityQueue) PushWithIndex(value int, i int) {
	pq.IndicesOfIndices.Set(i, len(pq.Window))
	pq.Window = append(pq.Window, value)
}

// Updates the queue and returns the max element
func (pq *PriorityQueue) NextWithIndex(pushed int, i int) int {
	j := pq.IndicesOfIndices.Get(i) // 3.1.
	pq.Window[j] = pushed
	heap.Fix(pq, j)
	return pq.Window[0]             // 3.2.
}

huangapple
  • 本文由 发表于 2022年5月19日 17:09:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/72301727.html
匿名

发表评论

匿名网友

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

确定