实现双端优先队列的Golang程序
双端优先队列(Double Ended Priority Queue,简称DEPQ)是一种扩展了标准优先队列功能的数据结构。在本文中,我们将使用两种方法在Golang中实现双端优先队列:第一种方法使用两个单独的堆来处理最大和最小优先级,而第二种方法则在单个堆上增加额外的信息以实现高效的查询操作。在代码示例中,我们将执行插入、检索、删除和更新等操作。
解释
双端优先队列是一种允许插入和删除操作的数据结构,同时可以高效地访问集合中的最大和最小元素。
Max Heap: Min Heap:
9 3
/ \ / \
7 5 4 6
/ /
3 5
在最大堆中,根节点包含最大值 [9],每个父节点的值都大于子节点,并且从上到下,数值递减。
在最小堆中,根节点包含最小值 [3],每个父节点的值都大于子节点,并且从上到下,数值递增。
算法
- 初始化两个堆,maxHeap和minHeap。
-
将元素与maxHeap和minHeap的根节点比较以确定其优先级。将元素插入到相应的堆中。如果大小差异超过1,则平衡堆。
-
从包含元素的堆中删除元素。如果大小差异超过1,则平衡堆。
-
返回maxHeap的根节点。
-
返回minHeap的根节点。
语法
type DEPQ struct {
maxHeap, minHeap []int
}
DEPQ结构包含了maxHeap和minHeap切片,可以高效地检索最高和最低优先级的元素。
type DEPQ struct {
heap []int
values map[int]int
}
该语法使用单个增强堆来实现DEPQ。DEPQ结构包含两个切片:堆用于存储优先级队列中的元素,而值用于跟踪元素的位置。增强堆结构包含堆切片,可以高效查询最高优先级和最低优先级的元素。
示例1
在这个示例中,我们使用两个单独的堆(maxHeap和minHeap)来实现Go中的双端优先级队列。Insert函数将元素插入两个堆中,而Delete函数会从两个堆中删除元素。GetMax和GetMin函数分别从DEPQ中检索最大和最小元素。
package main
import (
"container/heap"
"fmt"
)
type MaxHeap []int
func (h MaxHeap) Len() int { return len(h) }
func (h MaxHeap) Less(i, j int) bool { return h[i] > h[j] }
func (h MaxHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *MaxHeap) Push(x interface{}) { *h = append(*h, x.(int)) }
func (h *MaxHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
type MinHeap []int
func (h MinHeap) Len() int { return len(h) }
func (h MinHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h MinHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *MinHeap) Push(x interface{}) { *h = append(*h, x.(int)) }
func (h *MinHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
type DEPQ struct {
maxHeap *MaxHeap
minHeap *MinHeap
}
func NewDEPQ() *DEPQ {
maxHeap := &MaxHeap{}
minHeap := &MinHeap{}
heap.Init(maxHeap)
heap.Init(minHeap)
return &DEPQ{maxHeap, minHeap}
}
func (dq *DEPQ) Insert(val int) {
heap.Push(dq.maxHeap, val)
heap.Push(dq.minHeap, val)
}
func (dq *DEPQ) Delete(val int) {
for i := 0; i < len(*dq.maxHeap); i++ {
if (*dq.maxHeap)[i] == val {
heap.Remove(dq.maxHeap, i)
break
}
}
for i := 0; i < len(*dq.minHeap); i++ {
if (*dq.minHeap)[i] == val {
heap.Remove(dq.minHeap, i)
break
}
}
}
func (dq *DEPQ) GetMax() int {
if len(*dq.maxHeap) > 0 {
return (*dq.maxHeap)[0]
}
return -1
}
func (dq *DEPQ) GetMin() int {
if len(*dq.minHeap) > 0 {
return (*dq.minHeap)[0]
}
return -1
}
func main() {
dq := NewDEPQ()
dq.Insert(5)
dq.Insert(3)
dq.Insert(7)
dq.Insert(4)
dq.Insert(6)
fmt.Println("Maximum element:", dq.GetMax())
fmt.Println("Minimum element:", dq.GetMin())
dq.Delete(4)
fmt.Println("Maximum element after deletion:", dq.GetMax())
fmt.Println("Minimum element after deletion:", dq.GetMin())
}
输出
Maximum element: 7
Minimum element: 3
Maximum element after deletion: 7
Minimum element after deletion: 3
示例2
在这个示例中,我们使用一个堆来表示go语言中的双端优先队列。每个元素在堆中存储两次,一次作为最大元素,一次作为最小元素,使用DEPQNode结构体。DEPQ结构体包含堆和一个唯一标识符,以确保每个节点都有一个不同的标识符。Insert函数通过创建两个DEPQNode实例(一个用于最大值,一个用于最小值)并将它们添加到堆中来向DEPQ添加元素。GetMaximum和GetMinimum函数分别从DEPQ中检索最大和最小元素。Remove函数通过在堆中找到并移除元素的两个实例来从DEPQ中移除指定的元素。
package main
import (
"container/heap"
"fmt"
)
type DEPQNode struct {
value int
isMax, isMin bool
uniqueID int
}
type DEPQHeap []DEPQNode
func NewDEPQHeap() *DEPQHeap {
return &DEPQHeap{}
}
func (h DEPQHeap) Len() int { return len(h) }
func (h DEPQHeap) Less(i, j int) bool { return h[i].value < h[j].value }
func (h DEPQHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *DEPQHeap) Push(x interface{}) {
node := x.(DEPQNode)
*h = append(*h, node)
}
func (h *DEPQHeap) Pop() interface{} {
old := *h
n := len(old)
node := old[n-1]
*h = old[0 : n-1]
return node
}
type DoubleEndedPriorityQueue struct {
heap *DEPQHeap
}
func NewDoubleEndedPriorityQueue() *DoubleEndedPriorityQueue {
return &DoubleEndedPriorityQueue{
heap: NewDEPQHeap(),
}
}
func (dePQ *DoubleEndedPriorityQueue) Insert(value int) {
node := DEPQNode{value: value, isMax: true, isMin: true, uniqueID: len(*dePQ.heap)}
heap.Push(dePQ.heap, node)
}
func (dePQ *DoubleEndedPriorityQueue) GetMinimum() int {
if dePQ.heap.Len() == 0 {
return -1
}
return (*dePQ.heap)[0].value
}
func (dePQ *DoubleEndedPriorityQueue) GetMaximum() int {
if dePQ.heap.Len() == 0 {
return -1
}
return (*dePQ.heap)[dePQ.heap.Len()-1].value
}
func main() {
dePQ := NewDoubleEndedPriorityQueue()
dePQ.Insert(10)
dePQ.Insert(5)
dePQ.Insert(20)
fmt.Println("Minimum Element:", dePQ.GetMinimum())
fmt.Println("Maximum Element:", dePQ.GetMaximum())
}
输出
Minimum Element: 5
Maximum Element: 20
现实生活中的应用
医院患者管理
在医院中,患者分诊是根据其医疗状况进行优先级排序的过程。双端优先队列可以将病情最严重的患者存储在顶部(使用最大堆),而病情较轻的患者存储在底部(使用最小堆)。这使得医生可以快速处理重症患者,同时也能高效管理较不紧急的病例。
社交媒体动态
社交媒体平台通常根据用户参与度显示帖子。双端优先队列可以根据最高点赞或评论数将帖子优先排在顶部(使用最大堆),将不太受欢迎的帖子排在底部(使用最小堆)。这使用户可以在动态中看到热门内容和不太突出的帖子,提升他们的浏览体验。
结论
双端优先队列是标准优先队列的扩展,允许高效地检索最高和最低优先级的元素。在本文中,我们将探讨在go语言中实现双端优先队列的两种方法。第一种方法使用两个单独的堆来处理最大和最小优先级,而第二种方法则利用一个增强的堆。代码示例演示了在双端优先队列中插入、删除和检索元素的过程,展示了它们的实际应用和效率。