当前位置: 首页 > news >正文

TopK问题(堆排序)-- go

TopK问题(堆排序)

一、堆

1.1 堆的定义

完全二叉树 + 堆序性(指的是大顶堆/小顶堆)

大顶堆:节点本身的值为根的子树/树的各个节点的最大值(递归性理解:只需要节点大于两个子节点)

小顶堆:节点本身的值为根的子树/树的各个节点的最小值(递归性理解:只需要节点小于两个子节点)

1.2堆的存储

层序遍历后,可以放在一维数组/切片中,有切片索引和堆位置索引的规律:

节点索引为 i,其子节点为 2i+1、2i+2

1.3 堆的基操

上滤:节点向上移动(原因是下面的节点破环堆序性)-- 插入场景

下滤:节点向下移动(原因是上面的节点破环堆序性)-- 调整

1.4 建堆

自顶向下:保持顶部堆序性的建堆方法+ 破环底部 + 上滤

自底向上:保持底部堆序性的建堆方法+ 破环顶部 + 下滤(全插入再调整)

1.5 应用

堆排序:本质还是使用优先队列

优先队列:在go中实现heap接口(PList 为 优先队列类型)之后可以使用heap包的相关方法

// 这里采用 int 类型作为元素
// topK问题:采用堆排序的方式(优先队列的数据结构)// 实现优先队列
type PList []int// 实现go内置的heap接口
// 修改切片内容,只需要使用值接收者
func (p PList) Len() int{return len(p)
}func (p PList) Swap(i,j int){p[i], p[j] = p[j], p[i]
}// 大顶堆
func (p PList) Less(i,j int) bool{return p[i] > p[j]
}
// 修改切片本身,需要使用指针接收者
func (p *PList) Push(x interface{}){// 解引用出旧的切片old := *p// 类型转换后加入*p = append(old, x.(int))
}func (p *PList) Pop() interface{}{// 解引用出旧的切片old := *pn := len(old)// 弹出最后一个元素x := old[n-1]*p = old[0:n-1]return x
}

二、TopK问题

面试题 17.14. 最小K个数 - 力扣(LeetCode)

整体思路:创建大顶堆,将大元素全部放到大顶堆中,heap堆

func smallestK(arr []int, k int) []int {// 边界:if k <= 0 || k > len(arr) {return nil}// 创建大顶堆h := make(PList, k)// 先放入k个元素copy(h, arr[:k])// 初始化为堆结构heap.Init(&h)// 遍历剩余元素for _,num := range arr[k:]{// 因为是大顶堆,新元素小则需要修复if num < h[0]{h[0] = num// 索引0处的修改,需要修复heap.Fix(&h, 0)}}// 将堆中元素取出并返回result := make([]int, k)for i := 0; i < k; i++ {result[i] = heap.Pop(&h).(int)}return result
}// topK问题:采用堆排序的方式(优先队列的数据结构)// 实现优先队列
type PList []int// 实现go内置的heap接口
// 修改切片内容,只需要使用值接收者
func (p PList) Len() int{return len(p)
}func (p PList) Swap(i,j int){p[i], p[j] = p[j], p[i]
}// 大顶堆
func (p PList) Less(i,j int) bool{return p[i] > p[j]
}
// 修改切片本身,需要使用指针接收者
func (p *PList) Push(x interface{}){// 解引用出旧的切片old := *p// 类型转换后加入*p = append(old, x.(int))
}
// 大顶堆
func (p *PList) Pop() interface{}{// 解引用出旧的切片old := *pn := len(old)// 弹出最后一个元素x := old[n-1]*p = old[0:n-1]return x
}
// 采用小顶堆
func smallestK(arr []int, k int) []int {if k <= 0 || k > len(arr) {return nil}h := make(PList, k)copy(h, arr[:k])heap.Init(&h)for _,num := range arr[k:]{// 小顶堆:只允许大元素加入if num > h[0]{h[0] = numheap.Fix(&h, 0)}}result := make([]int, k)for i := 0; i < k; i++ {result[i] = heap.Pop(&h).(int)}return result
}type PList []intfunc (p PList) Len() int{return len(p)
}func (p PList) Swap(i,j int){p[i], p[j] = p[j], p[i]
}// 小顶堆: 小于时返回true
func (p PList) Less(i,j int) bool{return p[i] < p[j]
}func (p *PList) Push(x interface{}){old := *p*p = append(old, x.(int))
}func (p *PList) Pop() interface{}{old := *pn := len(old)x := old[n-1]*p = old[0:n-1]return x
}
http://www.xdnf.cn/news/1349515.html

相关文章:

  • MySQL存储过程入门
  • 中农具身导航赋能智慧农业!AgriVLN:农业机器人的视觉语言导航
  • PostgreSQL15——查询详解
  • Python 十进制转二进制
  • 【每天一个知识点】AIOps 与自动化管理
  • 使用隧道(Tunnel)连接PostgreSQL数据库(解决防火墙问题)(含Java实现代码)
  • AI实验管理神器:WandB全功能解析
  • 【文献阅读】Advances and Challenges in Large Model Compression: A Survey
  • `strncasecmp` 字符串比较函数
  • Unreal Engine IWYU Include What You Use
  • Vue 插槽(Slots)全解析2
  • ubuntu - 终端工具 KConsole安装
  • AI + 教育:个性化学习如何落地?教师角色转变与技术伦理的双重考验
  • SymPy 中抽象函数的推导与具体函数代入
  • Spring Ai 1.0.1中存在的问题:使用MessageChatMemoryAdvisor导致System未被正确的放在首位
  • c++最新进展
  • fdisk工具源码编译生成
  • DAY14-新世纪DL(DeepLearning/深度学习)战士:破(优化算法)2
  • 多线程下为什么用ConcurrentHashMap而不是HashMap
  • 【Android】 连接wifi时,强制应用使用流量
  • 【从零开始java学习|第九篇】方法的相关知识与练习
  • 【微服务的数据一致性分发问题】究极解决方案
  • 日志的配置
  • 一键部署openGauss6.0.2轻量版单节点
  • Spring原理
  • 最近 | 黄淮教务 | 小工具合集
  • 世界模型一种能够对现实世界环境进行仿真,并基于文本、图像、视频和运动等输入数据来生成视频、预测未来状态的生成式 AI 模型
  • Maxscript如何清理3dMax场景?
  • 打工人日报20250822
  • More Effective C++ 条款01:仔细区别 pointers 和 references