从golang中的优先级队列中删除元素

时间:2018-03-09 14:20:23

标签: go heap priority-queue

我从golang docs完全实现了优先级队列。我有兴趣一次删除多个元素,如heap.Remove(&queue, index1, index2, ...)

现在可以用直截了当的方式完成:

for _, event := range events {
    heap.Remove(&queue, event.getIndex())
}

但是这种方法有一个开销,因为每次调用heap.Remove都会重新组织树。如果我们可以首先删除所有不必要的元素,然后重新组织树,这似乎更有效。

如何实施?

2 个答案:

答案 0 :(得分:2)

由于堆的基础数据结构是一个切片,因此可以直接从切片中删除元素,然后再重新初始化堆。

从你的例子开始:

for _, event := range events {
    i := event.GetIndex()
    queue[i], queue[len(queue)-1] = queue[len(queue)-1], queue[i]
    queue = queue[:len(queue)-1]
}
heap.Init(&queue)

一个有效的例子:https://play.golang.org/p/-KMEilCm3t9

func main() {
    h := IntHeap{1, 5, 2, 9, 8, 3, 7}

    toRemove := 8
    for i := 0; i < len(h); i++ {
        n := h[i]
        if n == toRemove {
            h[i], h[len(h)-1] = h[len(h)-1], h[i]
            h = h[:len(h)-1]
            i--
        }
    }

    heap.Init(&h)
    fmt.Println(h)
}

答案 1 :(得分:1)

为了回答这个问题,我们首先需要了解堆是什么。堆是一种数据结构,允许我们根据它是Min Heap还是Max Heap来找到最大或最小值。为了快速完成这项工作,计算机会保留一棵树,这张图片总结得很好。这是最大堆:

Max-heap diagram, nine nodes

当然,计算机的记忆并没有在树上布置,它们是线性排列的。事实上,将切片堆放在切片中,这意味着您可以遍历切片并删除像您通常那样的元素,例如:

  for i:=0; i<len(heap); i++ {  
    for _, element := heap {
      if element == to_remove {
        heap = append(heap[:i], heap[i+1:])
        i--
      }
    }
  }