nodejs 14.0.0源码分析之优先队列

2024-03-27 21:32

本文主要是介绍nodejs 14.0.0源码分析之优先队列,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

nodejs了实现了一个优先队列,在重构定时器模块的时候,用到了这个数据结构。了解这个模块是分析定时器模块的基础。

'use strict';const {Array,Symbol,
} = primordials;const kCompare = Symbol('compare');
const kHeap = Symbol('heap');
const kSetPosition = Symbol('setPosition');
const kSize = Symbol('size');module.exports = class PriorityQueue {// 比较函数和节点移动位置后的回调函数constructor(comparator, setPosition) {if (comparator !== undefined)this[kCompare] = comparator;if (setPosition !== undefined)this[kSetPosition] = setPosition;// 用一个数组保存二叉堆的节点this[kHeap] = new Array(64);// 堆中的元素个数this[kSize] = 0;}// 默认的比较函数[kCompare](a, b) {return a - b;}// 插入堆insert(value) {const heap = this[kHeap];// 为了计算方便,从1开始存储数据const pos = ++this[kSize];heap[pos] = value;// 扩容if (heap.length === pos)heap.length *= 2;// 把元素存在最后一个叶子节点,往上冒this.percolateUp(pos);}// 取根节点peek() {return this[kHeap][1];}// pos代表那个元素需要往下沉percolateDown(pos) {const compare = this[kCompare];const setPosition = this[kSetPosition];const heap = this[kHeap];const size = this[kSize];const item = heap[pos];/*从需要下沉的节点开始,调整子树,size为元素个数,pos*2小于等于size说明pos位置的元素还有孩子,即还没沉到底*/while (pos * 2 <= size) {// 右孩子let childIndex = pos * 2 + 1;// childIndex > size说明没有右孩子,只有左孩子。否则说明有右孩子,则比较左右孩子,小于0说明右孩子大,则取值小的if (childIndex > size || compare(heap[pos * 2], heap[childIndex]) < 0)childIndex = pos * 2;/*拿到值小的节点和父节点比较,一旦需要交换位置的话,也满足二叉堆。否则如何和大的节点比较,同时大的节点满足上升的话,新的根节点比孩子大。4                         2                               3比如2   3,4要和2比,2上升变成4    3满足二叉堆,如果和3比则变成2    4,不满足二叉堆规则*/const child = heap[childIndex];// 比较值小的节点和当前需要下沉的节点,如果父节点比字节的值大,则满足二叉堆规则,不需要继续调整了if (compare(item, child) <= 0)break;// 否则说明父节点比子节点值小,更新子节点的位置信息if (setPosition !== undefined)setPosition(child, pos);// 子节点往上冒,子节点的位置空闲heap[pos] = child;// 继续调整子节点为根的子树pos = childIndex;}// pos就是item新的位置heap[pos] = item;if (setPosition !== undefined)setPosition(item, pos);}// pos代表那个元素需要往上冒percolateUp(pos) {const heap = this[kHeap];const compare = this[kCompare];const setPosition = this[kSetPosition];const item = heap[pos];// 大于1,根节点不需要往上冒了while (pos > 1) {// 完全二叉树,父和子的关系是子等于父索引*2和父索引*2加一const parent = heap[pos / 2 | 0];// 比父节点大,则不需要调整了if (compare(parent, item) <= 0)break;// 否则比父节点小,即更快到期,移动父节点往下沉,父节点的位置可用heap[pos] = parent;// 更新节的位置信息if (setPosition !== undefined)setPosition(parent, pos);// 再往上层比较,或0为了取整pos = pos / 2 | 0;}// pos为item合适的位置,直接赋值heap[pos] = item;if (setPosition !== undefined)setPosition(item, pos);}// 删除pos索引对应的元素removeAt(pos) {const heap = this[kHeap];// 元素少了一个const size = --this[kSize];// 把最后一个元素补上来成为该子树的根节点,然后开始调整heap[pos] = heap[size + 1];// 删除最后一个元素,即刚才补上去的那个heap[size + 1] = undefined;// 还有元素并且不是最后一个,即被删除的不是倒数第二个元素(倒数第二个叶子)if (size > 0 && pos <= size) {/*二叉堆只保证父子节点的大小关系,不保证左右孩子的大小关系,不像二叉搜索树,所以某一个子树的叶子节点可能会比另一个子树的根大如果不是根节点并且比父节点小,说明比父节点为根节点的子树所有节点都小,则往上冒,如果是根节点则直接往下沉调整如果不是根节点但是比父节点大,也有可能比父节点为根的子树中剩下的节点大,所以往下沉调整*/if (pos > 1 && this[kCompare](heap[pos / 2 | 0], heap[pos]) > 0)this.percolateUp(pos);elsethis.percolateDown(pos);}}// 删除某个值对于的节点remove(value) {const heap = this[kHeap];// 找到位置,然后删除const pos = heap.indexOf(value);if (pos < 1)return false;this.removeAt(pos);return true;}// 删除根节点,重新调整二叉堆shift() {const heap = this[kHeap];const value = heap[1];if (value === undefined)return;this.removeAt(1);return value;}
};

nodejs的优先队列是基于二叉堆(小根堆)实现的。用数组的方式实现二叉堆。主要的操作包括插入,删除。堆一直保证最小的值是根节点。他是一棵完全二叉树,他的父子节点是父节点的值小于子节点的值,但是不保证兄弟节点间的关系。

1 插入

二叉堆的插入是首先在树的最后位置(对于数组来说就是最后一个元素)插入新增的节点,然后该新节点一直和父节点比较,小于父节点的话就交换,直到大于父节点。这样可以保证根一直是最小值。

2 删除

删除操作首先把需要删除的节点直接删掉,然后把堆的最后一个节点补到被删除节点的位置如果大于父节点,则往下比较。否则往上比较(删除的是根节点的话直接往下比较)。同样,这样的调整保证了根节点是最小值。

3 往上冒

往上冒比较简单,只需要比较父子节点的值,子节点小的话直接往上冒。因为父节点比左右孩子都小,如果当前比较的节点比父小,说明他也比亲兄弟节点小。父子交换可以满足二叉堆的特性。

4 往下沉

往下沉比往上冒父复杂点,他首先要找出孩子中的最小值,然后才能进行比较,交换。见代码注释。

这篇关于nodejs 14.0.0源码分析之优先队列的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853451

相关文章

[职场] 公务员的利弊分析 #知识分享#经验分享#其他

公务员的利弊分析     公务员作为一种稳定的职业选择,一直备受人们的关注。然而,就像任何其他职业一样,公务员职位也有其利与弊。本文将对公务员的利弊进行分析,帮助读者更好地了解这一职业的特点。 利: 1. 稳定的职业:公务员职位通常具有较高的稳定性,一旦进入公务员队伍,往往可以享受到稳定的工作环境和薪资待遇。这对于那些追求稳定的人来说,是一个很大的优势。 2. 薪资福利优厚:公务员的薪资和

springboot家政服务管理平台 LW +PPT+源码+讲解

3系统的可行性研究及需求分析 3.1可行性研究 3.1.1技术可行性分析 经过大学四年的学习,已经掌握了JAVA、Mysql数据库等方面的编程技巧和方法,对于这些技术该有的软硬件配置也是齐全的,能够满足开发的需要。 本家政服务管理平台采用的是Mysql作为数据库,可以绝对地保证用户数据的安全;可以与Mysql数据库进行无缝连接。 所以,家政服务管理平台在技术上是可以实施的。 3.1

高仿精仿愤怒的小鸟android版游戏源码

这是一款很完美的高仿精仿愤怒的小鸟android版游戏源码,大家可以研究一下吧、 为了报复偷走鸟蛋的肥猪们,鸟儿以自己的身体为武器,仿佛炮弹一样去攻击肥猪们的堡垒。游戏是十分卡通的2D画面,看着愤怒的红色小鸟,奋不顾身的往绿色的肥猪的堡垒砸去,那种奇妙的感觉还真是令人感到很欢乐。而游戏的配乐同样充满了欢乐的感觉,轻松的节奏,欢快的风格。 源码下载

高度内卷下,企业如何通过VOC(客户之声)做好竞争分析?

VOC,即客户之声,是一种通过收集和分析客户反馈、需求和期望,来洞察市场趋势和竞争对手动态的方法。在高度内卷的市场环境下,VOC不仅能够帮助企业了解客户的真实需求,还能为企业提供宝贵的竞争情报,助力企业在竞争中占据有利地位。 那么,企业该如何通过VOC(客户之声)做好竞争分析呢?深圳天行健企业管理咨询公司解析如下: 首先,要建立完善的VOC收集机制。这包括通过线上渠道(如社交媒体、官网留言

基于Java医院药品交易系统详细设计和实现(源码+LW+调试文档+讲解等)

💗博主介绍:✌全网粉丝10W+,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码+数据库🌟 感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,希望帮助更多的人  Java精品实战案例《600套》 2023-2025年最值得选择的Java毕业设计选题大全:1000个热

美容美发店营销版微信小程序源码

打造线上生意新篇章 一、引言:微信小程序,开启美容美发行业新纪元 在数字化时代,微信小程序以其便捷、高效的特点,成为了美容美发行业营销的新宠。本文将带您深入了解美容美发营销微信小程序,探讨其独特优势及如何助力商家实现业务增长。 二、微信小程序:美容美发行业的得力助手 拓宽客源渠道:微信小程序基于微信社交平台,轻松实现线上线下融合,帮助商家快速吸引潜在客户,拓宽客源渠道。 提升用户体验:

风水研究会官网源码系统-可展示自己的领域内容-商品售卖等

一款用于展示风水行业,周易测算行业,玄学行业的系统,并支持售卖自己的商品。 整洁大气,非常漂亮,前端内容均可通过后台修改。 大致功能: 支持前端内容通过后端自定义支持开启关闭会员功能,会员等级设置支持对接官方支付支持添加商品类支持添加虚拟下载类支持自定义其他类型字段支持生成虚拟激活卡支持采集其他站点文章支持对接收益广告支持文章评论支持积分功能支持推广功能更多功能,搭建完成自行体验吧! 原文

HTML5文旅文化旅游网站模板源码

文章目录 1.设计来源文旅宣传1.1 登录界面演示1.2 注册界面演示1.3 首页界面演示1.4 文旅之行界面演示1.5 文旅之行文章内容界面演示1.6 关于我们界面演示1.7 文旅博客界面演示1.8 文旅博客文章内容界面演示1.9 联系我们界面演示 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目录 源码下载万套模板,程序开发,在线开发,在线沟通 作者:xcLeigh

打包体积分析和优化

webpack分析工具:webpack-bundle-analyzer 1. 通过<script src="./vue.js"></script>方式引入vue、vuex、vue-router等包(CDN) // webpack.config.jsif(process.env.NODE_ENV==='production') {module.exports = {devtool: 'none

Java中的大数据处理与分析架构

Java中的大数据处理与分析架构 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们来讨论Java中的大数据处理与分析架构。随着大数据时代的到来,海量数据的存储、处理和分析变得至关重要。Java作为一门广泛使用的编程语言,在大数据领域有着广泛的应用。本文将介绍Java在大数据处理和分析中的关键技术和架构设计。 大数据处理与