热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

golang优先级队列

  containerheap本文是Go标准库中containerheap包文档的翻译,原文地址为: https:golang.orgpkgcontainerheap概述包heap

 

 


container/heap

本文是 Go 标准库中 container/heap 包文档的翻译, 原文地址为: https://golang.org/pkg/container/heap/


概述

包 heap 为所有实现了 heap.Interface 的类型提供堆操作。 一个堆即是一棵树, 这棵树的每个节点的值都比它的子节点的值要小, 而整棵树最小的值位于树根(root), 也即是索引 0 的位置上。

堆是实现优先队列的一种常见方法。 为了构建优先队列, 用户在实现堆接口时, 需要让 Less() 方法返回逆序的结果, 这样就可以在使用 Push 添加元素的同时, 通过 Pop 移除队列中优先级最高的元素了。 具体的实现请看接下来展示的优先队列例子。


示例:整数堆

// 这段代码演示了如何使用堆接口构建一个整数堆。
package main
import (
"container/heap"
"fmt"
)
// IntHeap 是一个由整数组成的最小堆。
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x interface{}) {
// Push 和 Pop 使用 pointer receiver 作为参数,
// 因为它们不仅会对切片的内容进行调整,还会修改切片的长度。
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
// 这个示例会将一些整数插入到堆里面, 接着检查堆中的最小值,
// 之后按顺序从堆里面移除各个整数。
func main() {
h := &IntHeap{2, 1, 5}
heap.Init(h)
heap.Push(h, 3)
fmt.Printf("minimum: %d\n", (*h)[0])
for h.Len() > 0 {
fmt.Printf("%d ", heap.Pop(h))
}
}

执行结果:

minimum: 1
1 2 3 5


示例:优先队列

// 这段代码演示了如何使用堆接口构建一个优先队列。
package main
import (
"container/heap"
"fmt"
)
// Item 是优先队列中包含的元素。
type Item struct {
value string // 元素的值,可以是任意字符串。
priority int // 元素在队列中的优先级。
// 元素的索引可以用于更新操作,它由 heap.Interface 定义的方法维护。
index int // 元素在堆中的索引。
}
// 一个实现了 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].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{}) {
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
}
// 更新函数会修改队列中指定元素的优先级以及值。
func (pq *PriorityQueue) update(item *Item, value string, priority int) {
item.value = value
item.priority = priority
heap.Fix(pq, item.index)
}
// 这个示例首先会创建一个优先队列,并在队列中包含一些元素
// 接着将一个新元素添加到队列里面,并对其进行操作
// 最后按优先级有序地移除队列中的各个元素。
func main() {
// 一些元素以及它们的优先级。
items := map[string]int{
"banana": 3, "apple": 2, "pear": 4,
}
// 创建一个优先队列,并将上述元素放入到队列里面,
// 然后对队列进行初始化以满足优先队列(堆)的不变性。
pq := make(PriorityQueue, len(items))
i := 0
for value, priority := range items {
pq[i] = &Item{
value: value,
priority: priority,
index: i,
}
i++
}
heap.Init(&pq)
// 插入一个新元素,然后修改它的优先级。
item := &Item{
value: "orange",
priority: 1,
}
heap.Push(&pq, item)
pq.update(item, item.value, 5)
// 以降序形式取出并打印队列中的所有元素。
for pq.Len() > 0 {
item := heap.Pop(&pq).(*Item)
fmt.Printf("%.2d:%s ", item.priority, item.value)
}
}

执行结果:

05:orange 04:pear 03:banana 02:apple


Fix 函数

func Fix(h Interface, i int)

在索引 i 上的元素的值发生变化之后, 重新修复堆的有序性。 先修改索引 i 上的元素的值然后再执行 Fix , 跟先调用 Remove(h, i) 然后再使用 Push 操作将新值重新添加到堆里面的做法具有同等的效果, 但前者所需的计算量稍微要少一些。

Fix 函数的复杂度为 O(log(n)) , 其中 n 等于 h.Len() 。


Init 函数

func Init(h Interface)

在执行任何堆操作之前, 必须对堆进行初始化。 Init 操作对于堆不变性(invariants)具有幂等性, 无论堆不变性是否有效, 它都可以被调用。

Init 函数的复杂度为 O(n) , 其中 n 等于 h.Len() 。


Pop 函数¶

func Pop(h Interface) interface{}

Pop 函数根据 Less 的结果, 从堆中移除并返回具有最小值的元素, 等同于执行 Remove(h, 0) 。

Pop 函数的复杂度为 O(log(n)) , 其中 n 等于 h.Len() 。


Push 函数

func Push(h Interface, x interface{})

Push 函数将值为 x 的元素推入到堆里面, 该函数的复杂度为 O(log(n)) , 其中 n 等于 h.Len() 。


Remove 函数

func Remove(h Interface, i int) interface{}

Remove 函数将移除堆中索引为 i 的元素, 该函数的复杂度为 O(log(n)) , 其中 n 等于 h.Len() 。


Interface 类型

任何实现了 heap.Interface 接口的类型, 都可以用作带有以下不变性的最小堆, (换句话说, 这个堆在为空、已排序或者调用 Init 之后, 应该具有以下性质):

!h.Less(j, i) for 0 <= i

注意, 这个接口中的 Push 和 Pop 都是由 heap 包的实现负责调用的。 因此用户在向堆添加元素又或者从堆中移除元素时, 需要使用 heap.Push 以及 heap.Pop :

type Interface interface {
sort.Interface
Push(x interface{}) // 将 x 添加为元素 Len()
Pop() interface{} // 移除并返回元素 Len() - 1
}

推荐阅读
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • 基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析
    基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析 ... [详细]
  • 题目链接:POJ 2777。问题描述:给定一个区域,需要进行多次涂色操作,并在每次操作后查询某个区间内的不同颜色数量。解决方案:由于题目中颜色种类不超过30种,可以利用线段树的懒惰更新策略来高效处理这些操作。通过懒惰标记,避免了不必要的节点更新,从而显著提高了算法的效率。此外,该方法还能有效应对大规模数据输入,确保在合理的时间内完成所有操作。 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
  • 在iOS开发中,基于HTTPS协议的安全网络请求实现至关重要。HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer)是一种旨在提供安全通信的HTTP扩展,通过SSL/TLS加密技术确保数据传输的安全性和隐私性。本文将详细介绍如何在iOS应用中实现安全的HTTPS网络请求,包括证书验证、SSL握手过程以及常见安全问题的解决方法。 ... [详细]
  • 经过两天的努力,终于成功解决了半平面交模板题POJ3335的问题。原来是在`OnLeft`函数中漏掉了关键的等于号。通过这次训练,不仅加深了对半平面交算法的理解,还提升了调试和代码实现的能力。未来将继续深入研究计算几何的其他核心问题,进一步巩固和拓展相关知识。 ... [详细]
  • 本文深入探讨了佩尔方程 \( x^2 - dy^2 = 1 \) 的递推关系式。通过构造特定的矩阵并利用矩阵快速幂的方法,可以高效地计算出该方程的第 k 组解。此外,文章还详细分析了递推关系式的数学背景及其在数论中的应用,为相关研究提供了坚实的理论基础。 ... [详细]
  • 如何利用Java 5 Executor框架高效构建和管理线程池
    Java 5 引入了 Executor 框架,为开发人员提供了一种高效管理和构建线程池的方法。该框架通过将任务提交与任务执行分离,简化了多线程编程的复杂性。利用 Executor 框架,开发人员可以更灵活地控制线程的创建、分配和管理,从而提高服务器端应用的性能和响应能力。此外,该框架还提供了多种线程池实现,如固定线程池、缓存线程池和单线程池,以适应不同的应用场景和需求。 ... [详细]
  • 在洛谷 P1344 的坏牛奶追踪问题中,第一问要求计算最小割,而第二问则需要找到割边数量最少的最小割。通过为每条边附加一个单位权值,可以在求解最小割时优先选择边数较少的方案,从而同时解决两个问题。这种策略不仅简化了问题的求解过程,还确保了结果的最优性。 ... [详细]
  • 寒假作业解析:第三周 2月12日 第7题
    尽快完成之前的练习任务!每日一练2.1 Problem A Laurenty and Shop 的题目要求是选择两条不同的路线以最小化总的等待时间。简要分析:通过对比不同路线的等待时间,可以找到最优解。此问题可以通过动态规划或贪心算法来解决,具体取决于路线的复杂性和约束条件。 ... [详细]
  • 蓝桥杯算法实战:节点选取策略优化分析
    本文针对蓝桥杯算法竞赛中的节点选取策略进行了深入分析与优化。通过对比不同节点选择方法的效果,提出了基于贪心算法和动态规划的综合优化方案,旨在提高算法效率和准确性。实验结果表明,该优化策略在处理大规模数据集时表现出色,显著提升了算法性能。 ... [详细]
  • 在解决区间相关问题时,我发现自己经常缺乏有效的思维方式,即使是简单的题目也常常需要很长时间才能找到解题思路,而一旦得到提示便能迅速理解。题目要求对一个包含n个元素的数组进行操作,并给出一个参数k,具体任务是…… ... [详细]
  • 2018 HDU 多校联合第五场 G题:Glad You Game(线段树优化解法)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6356在《Glad You Game》中,Steve 面临一个复杂的区间操作问题。该题可以通过线段树进行高效优化。具体来说,线段树能够快速处理区间更新和查询操作,从而大大提高了算法的效率。本文详细介绍了线段树的构建和维护方法,并给出了具体的代码实现,帮助读者更好地理解和应用这一数据结构。 ... [详细]
  • 在当前的软件开发领域,Lua 作为一种轻量级脚本语言,在 .NET 生态系统中的应用逐渐受到关注。本文探讨了 Lua 在 .NET 环境下的集成方法及其面临的挑战,包括性能优化、互操作性和生态支持等方面。尽管存在一定的技术障碍,但通过不断的学习和实践,开发者能够克服这些困难,拓展 Lua 在 .NET 中的应用场景。 ... [详细]
author-avatar
mobiledu2502889883
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有