go实现利用最大堆寻找最小k个数
作者 | 陌无崖
转载请联系授权
导语
昨天分享了寻找最小k个数的算法是,那么有没有更为迅速的方法呢?今天就来分享关于如何使用最大堆进行解决。
什么是堆
我太懒了,直接上我画好的思维导图吧哈哈,获取高清的也可以关注我的公众号,后台回复【堆】
思路设计
知道了如上定义,我们就可以将容量为K的最大堆存储我们的最小k个数,因此我们仍然可以按照之前的方法假设堆中存储的仍然是最小的k个数(不懂的可以看我的上一篇文章),再通过比较替换或不替换堆来最终找到我们的最小的k个数。此解法与解法二类似但由于使用堆时进行查找或更新的时间复杂度降低到了O(logk),那么通过遍历剩余的n-k个数,那么最坏情况下的时间复杂度为O(k + (n-k)logk) = O(nlogk)。这里的O(k)为建堆时的时间复杂度。
因此我们需要建堆,通过以上的分析我们可以用一维数组存储我们的堆,我们先来看一个完全二叉树找一下规律
我们将1,2,3,4,5分别作为下标,在上个图片的思路中,我们可以发现每次我们的遍历刚开始指向的是一个由子节点的父节点,在下图中可知子节点(i)和父节点(l)之间的关系是2 * i + 1 = l,且在同一深度相邻节点相差为1,由上图可知,我们在遍历父节点比较时,依次会经过5,4,3,2,1,0这些下标指向的数值。因此我们可以依次为循环,每次循环的操作都是父节点和子节点进行比较。
代码分析
(1) 循环每一个父节点
(2) 在子节点中找到最大值和父节点比较,若子节点大,则替换
(3) 每次提换后需要记录新的父节点,重新和子节点比较,替换,如下标为2和5的进行替换后,还要保证下标5(原来的下标2)是否满足最大堆性质。因为是同样的操作,因此该过程仍然是一个循环,循环结束的标志是最后一层的叶节点。
完整代码
func BuildMaxHeap(data []int) {
for i := len(data)/2 - 1; i >= 0; i-- {
adjustDown(data, i)
}
}
func adjustDown(data []int, i int) {
for largest := 2*i + 1; largest < len(data); largest = 2*largest + 1 {
if largest == len(data)-1 {
if data[largest] > data[i] {
// fmt.Println(data[largest], "和", data[i], "进行交换")
data[largest], data[i] = data[i], data[largest]
i = largest
} else {
// fmt.Println(data[largest], "不和", data[i], "进行交换")
}
} else {
if data[largest+1] > data[largest] && data[largest+1] > data[i] {
// fmt.Println(data[largest+1], "和", data[i], "进行交换")
data[largest+1], data[i] = data[i], data[largest+1]
i = largest
} else if data[largest+1] < data[largest] && data[largest] > data[i] {
// fmt.Println(data[largest], "和", data[i], "进行交换")
data[largest], data[i] = data[i], data[largest]
i = largest
} else {
// fmt.Println(data[largest], "或", data[largest+1], "不和", data[i], "进行交换")
}
}
}
}
// 维护最大堆
func topK(data []int, k int) {
// 建立前K个数的最大堆
BuildMaxHeap(data[0:k])
for i := k; i < len(data); i++ {
if data[i] < data[0] { //如果剩余的数中有小的数则替换
data[i], data[0] = data[0], data[i]
adjustDown(data[0:k], 0)
}
}
}
- Apache+wsgi+flask部署
- “勒索病毒”到底会勒索啥,尽可以做到让全球对之恐惧无奈!
- 解决win10 关键错误开始菜单和cortana无法工作 的问题(转-真的成功了)
- “AS3.0高级动画编程”学习:第二章转向行为(下)
- windows系统中eclipse C开发环境的架设
- 5个酷毙的Python工具
- ”盒模型“之如何防止边框和内边距把元素撑开
- excel中的不同类型图表叠加
- 这几天遇到的关于IE6/sql2008/win2003的奇怪bug
- 基于Web的工作流管理系统的设计与实现
- 这是对position讲解最通俗易懂的版本了。
- 你到底该如何看待比特币?
- OpenApplus小程序容器
- 点名了,最具投资价值的50家物联网企业名单发布
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [周末往期回顾]DB_CREATE_FILE_DEST,DB_CREATE_ONLINE_LOG_DEST_n
- 【DB宝18】在Docker中安装使用MySQL高可用之MGR
- [周末往期回顾]redis的介绍及安装
- [Oracle 日常管理]使用BBED定位数据位置
- [Oracle 日常管理]表的相关操作
- JsonPath实践(二)
- C# 使用OpenCV在一张图片里寻找人脸
- 【DB笔试面试858】在Oracle中,ipcs和ipcrm命令的作用有哪些?
- Qt音视频开发13-mpv录像存储
- Oracle参数解析(spfile)
- ROS2机器人笔记20-08-18
- C sharp实例:华盾武器门数据接收和解析
- JsonPath实践(三)
- 有序链表转换二叉搜索树
- 128. 最长连续序列