Golang heap源码简单走读
golang heap小根堆源码走读
heap概览
在golang中,通过heap给出了一个实现小根堆的接口。
type Interface interface {sort.InterfacePush(x interface{}) Pop() interface{}
}
由于小根堆中,需要根据容器中的元素大小来进行比较以确定元素在堆中的位置。因此也需要实现sort的接口。
type Interface interface {Len() intLess(i, j int) boolSwap(i, j int)
}
因此,如果需要实现一个heap,需要实现Push(),Pop()(从堆顶弹出元素),Len(),Less()(进行元素之间比较的方法)以及Swap()方法。
heap已经实现的方法
heap的初始化
func Init(h Interface) {n := h.Len()for i := n/2 - 1; i >= 0; i-- {down(h, i, n)}
}
在heap的初始化方法中,值得注意的是,不同于java方法,在调用这个方法的时候,堆中的元素容器应该已经完成了数据的存放,这里的初始化不是初始化存储空间返回一个空的容器,而是对一个已经充满元素的容器进行堆排序。首先会获取堆的大小n,取决于堆的性质,将会从堆的n/2-1位置开始通过down()方法初始化,这个位置是堆中倒数第二层最后一个拥有子节点的节点,之后将会不断从当前层不断向左,遍历完当前层之后再从上一层的最右边开始。
func down(h Interface, i0, n int) bool {i := i0 // i是方法中当前节点的下标for {j1 := 2*i + 1 // 获取当前节点的左子节点if j1 >= n || j1 < 0 { break // 如果当前节点的左子节点不存在则结束这一轮}j := j1 // j为当前节点的左子节点if j2 := j1 + 1; j2 < n && h.Less(j2, j1) { // 此处Less()方法为上文提到需要扩展实现的元素比较方法j = j2 // 将节点的左节点和右节点进行比较,j赋值为其中较小的下标}if !h.Less(j, i) {break }h.Swap(i, j) // 如果当前节点小于其子节点中的较小值,通过扩展的Swap()方法交换,将较小的值替换到父节点上,并且将会从当前节点继续往下与其子节点比较,直到达到最底层或者其两个子节点逗都比自己大i = j}return i > i0
}
顾名思义,down()实则是将一个节点不断从堆中不断下移直到达到其对应位置的一个过程。由于n/2-1保证了遍历的开始位置是堆中最后一个拥有子节点的位置,因此可以保证最后一层每一个子节点都能参与到一轮小根堆的初始化。一轮down()下来,将会保证容器中的最小值将会处于堆顶,只需要通过Pop()方法将栈顶的元素弹出就可以得到堆中最小的值。这可以适用于优先级队列等场景的实现。
heap的添加
func Push(h Interface, x interface{}) {h.Push(x)up(h, h.Len()-1)
}
当通过Push()方法往堆中添加元素的时候,可以先简单的将元素放到最后一层的叶子节点上,之后通过up()方法从最后一个子节点开始,将该新元素从堆底up到堆中的一个合适的位置上。
func up(h Interface, j int) {for {i := (j - 1) / 2 // 当前节点的父节点if i == j || !h.Less(j, i) {break}h.Swap(i, j) // 如果当前节点小于其父节点,将该节点与其父节点交换,并继续从新的位置向其父节点进行比较,直到下标为0达到堆顶或者遇到比其更小的父节点j = i}
}
对应down()的取名,up()是将一个节点从当前位置不断往堆的更上层前进的过程。这里的Push()操作的时间复杂度为O(logn)。
heap的弹出
func Pop(h Interface) interface{} {n := h.Len() - 1h.Swap(0, n)down(h, 0, n)return h.Pop()
}
Heap的弹出,只需要将堆顶的元素与堆的末尾元素调换,将其放到堆的末尾默认移除,不参与后续堆的调整即可。之后将当前所处的堆顶元素通过down()方法不断下移到其应该处在的位置即可。
Golang heap源码简单走读相关推荐
- android 点击事件消费,Android View事件分发和消费源码简单理解
Android View事件分发和消费源码简单理解 前言: 开发过程中觉得View事件这块是特别烧脑的,看了好久,才自认为看明白.中间上网查了下singwhatiwanna粉丝的读书笔记,有种茅塞顿开 ...
- Hessian 源码简单分析
Hessian 源码简单分析 Hessian 是一个rpc框架, 我们需要先写一个服务端, 然后在客户端远程的调用它即可. 服务端: 服务端通常和spring 做集成. 首先写一个接口: public ...
- 线程的3种实现方式并深入源码简单分析实现原理
前言 本文介绍下线程的3种实现方式并深入源码简单的阐述下原理 三种实现方式 Thread Runnable Callable&Future 深入源码简单刨析 Thread Thread类实现了 ...
- poco源码简单分析
自动化工具poco源码简单分析 Airtest简介 Airtest是网易游戏开源的一款UI自动化测试项目,目前处于公开测试阶段,该项目分为AirtestIDE.Airtest.Poco.Testlab ...
- FFmpeg的HEVC解码器源码简单分析:概述
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- FFmpeg的HEVC解码器源码简单分析:解码器主干部分
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- JSP 编译和运行过程与JSP源码简单分析
JSP 编译和运行过程与JSP转移源码简单分析 Web容器处理JSP文件请求的执行过程主要包括以下4个部分: 1. 客户端发出Request请求 2. JSP Container 将JSP转译成Ser ...
- 微信授权2.0php源码,微信网页授权(OAuth2.0) PHP 源码简单实现
微信网页授权(OAuth2.0) PHP 源码简单实现 来源:中文源码网 浏览: 次 日期:2018年9月2日 [下载文档: 微信网页授权(OAuth2.0) PHP 源码简单实现.tx ...
- golangsha1解码_如何阅读Golang的源码?
Go 的源码在安装包的 src/ 目录下.怎么看它的源码呢?直接看吧!没人教的情况下,只能自己撸了.当然,这种内容一般也不会有人教. 怎么撸? Go 源码中,应该可分为与语言息息相关的部分,和官方提供 ...
最新文章
- 2021全国高校计算机能力挑战赛(初赛)C语言
- 链家租房信息案例数据分析
- 微信小程序实例开发教程之知乎新闻
- java主窗体设计代码_java窗体设计+GUI经典代码全放送
- hadoop集群配置与启动
- matlab下删除文件或文件夹
- 抛出这8个问题,检验你是否真的会ThreadLocal
- action链接html,如何使用@ html.actionlink删除链接文本
- 一家中国公司把城市变成了AI版《清明上河图》
- ubuntu无法定位软件包的问题
- 如何将PDF转换成jpg图片?教你2种免费方法
- 中国裁判文书网爬虫分析
- 揭晓网站建设对于企业发展的重要作用
- Windows安装TortoiseSVN
- C++学习(complex类)
- python 跳过_如果文件已经存在,Python将跳过一个函数
- VueX 以及axios
- Java中的冒泡排序,Comparator接口和Comparable接口的简单使用
- intellij idea 2016 注册码
- js前端通过身份证号判断年龄、性别、出生日期。
热门文章
- Python使用pdfkit、wkhtmltopdf将html转换为pdf错误记录文档
- Android之选项卡
- JS手动实现一个new操作符
- 机器学习线性回归_机器学习实例--线性回归
- vue——懒加载(异步延迟和彻底懒加载)
- java中对date的一些处理以及获取date
- lcd1602怎么利用按键清屏_边学边练,8个LCD1602精选电路方案大合辑
- geoserver rest 导入shape文件错误
- (3)分布式下的爬虫Scrapy应该如何做-递归爬取方式,数据输出方式以及数据库链接...
- 关于Android中Intent传递Serialzilable数据的问题