数据结构与算法专题——第二题 优先队列

前段时间玩小爬虫的时候,我把url都是放在内存队列里面,有时我们在抓取url的时候,通过LCS之类的相似度比较,发现某些url是很重要的,需要后端解析服务器优先处理,针对这种优先级比较大的url,普通的队列还是苦逼的在做FIFO操作,现在我们的需求就是优先级大的优先服务,要做优先队列,非堆莫属。

一:堆结构

1:性质

堆是一种很松散的序结构树,只保存了父节点和孩子节点的大小关系,并不规定左右孩子的大小,不像排序树那样严格,又因为堆是一种完全二叉树,设节点为i,则i/2是i的父节点,2i是i的左孩子,2i+1是i的右孩子,所以在实现方式上可以采用轻量级的数组。

2:用途

如果大家玩过微软的MSMQ的话,就会发现它其实也是一个优先队列,还有刚才说的抓取url,不过很遗憾,为什么.net类库中没有优先队列呢?而java1.5中就已经支持了。

3:实现

<1>堆结构节点定义:

我们在每个节点上定义一个level,表示该节点的优先级,也是构建堆时采取的依据。


/// <summary>/// 定义一个数组来存放节点/// </summary>private List<HeapNode> nodeList = new List<HeapNode>();/// <summary>/// 堆节点定义/// </summary>public class HeapNode{/// <summary>/// 实体数据/// </summary>public T t { get; set; }/// <summary>/// 优先级别 1-10个级别 (优先级别递增)/// </summary>public int level { get; set; }public HeapNode(T t, int level){this.t = t;this.level = level;}public HeapNode() { }}

<2> 入队操作

入队操作时我们要注意几个问题:

①:完全二叉树的构建操作是“从上到下,从左到右”的形式,所以入队的节点是放在数组的最后,也就是树中叶子层的有序最右边空位。

②:当节点插入到最后时,有可能破坏了堆的性质,此时我们要进行“上滤操作”,当然时间复杂度为O(logN)。

当我将节点“20”插入到堆尾的时候,此时破坏了堆的性质,从图中我们可以清楚的看到节点“20”的整个上滤过程,有意思吧,还有一点就是:获取插入节点的父亲节点的算法是:parent=list.count/2-1。这也得益于完全二叉树的特性。


#region  添加操作/// <summary>/// 添加操作/// </summary>public void Eequeue(T t, int level = 1){//将当前节点追加到堆尾nodeList.Add(new HeapNode(t, level));//如果只有一个节点,则不需要进行筛操作if (nodeList.Count == 1)return;//获取最后一个非叶子节点int parent = nodeList.Count / 2 - 1;//堆调整UpHeapAdjust(nodeList, parent);}#endregion#region 对堆进行上滤操作,使得满足堆性质/// <summary>/// 对堆进行上滤操作,使得满足堆性质/// </summary>/// <param name="nodeList"></param>/// <param name="index">非叶子节点的之后指针(这里要注意:我们/// 的筛操作时针对非叶节点的)/// </param>public void UpHeapAdjust(List<HeapNode> nodeList, int parent){while (parent >= 0){//当前index节点的左孩子var left = 2 * parent + 1;//当前index节点的右孩子var right = left + 1;//parent子节点中最大的孩子节点,方便于parent进行比较//默认为left节点var max = left;//判断当前节点是否有右孩子if (right < nodeList.Count){//判断parent要比较的最大子节点max = nodeList[left].level < nodeList[right].level ? right : left;}//如果parent节点小于它的某个子节点的话,此时筛操作if (nodeList[parent].level < nodeList[max].level){//子节点和父节点进行交换操作var temp = nodeList[parent];nodeList[parent] = nodeList[max];nodeList[max] = temp;//继续进行更上一层的过滤parent = (int)Math.Ceiling(parent / 2d) - 1;}else{break;}}}#endregion

<3> 出队操作

从图中我们可以看出,优先级最大的节点会在一阵痉挛后上升到堆顶,出队操作时,我们采取的方案是:弹出堆顶元素,然后将叶子层中的最右子节点赋给堆顶,同样这时也会可能存在破坏堆的性质,最后我们要被迫进行下滤操作。

从图中可以看出:首先将堆顶20弹出,然后将7赋给堆顶,此时堆性质遭到破坏,最后我们清楚的看到节点7的下滤过程,从摊还分析的角度上来说,下滤的层数不超过2-3层,所以整体上来说出队的时间复杂度为一个常量O(1)。


#region 优先队列的出队操作/// <summary>/// 优先队列的出队操作/// </summary>/// <returns></returns>public HeapNode Dequeue(){if (nodeList.Count == 0)return null;//出队列操作,弹出数据头元素var pop = nodeList[0];//用尾元素填充头元素nodeList[0] = nodeList[nodeList.Count - 1];//删除尾节点nodeList.RemoveAt(nodeList.Count - 1);//然后从根节点下滤堆DownHeapAdjust(nodeList, 0);return pop;}#endregion#region  对堆进行下滤操作,使得满足堆性质/// <summary>/// 对堆进行下滤操作,使得满足堆性质/// </summary>/// <param name="nodeList"></param>/// <param name="index">非叶子节点的之后指针(这里要注意:我们/// 的筛操作时针对非叶节点的)/// </param>public void DownHeapAdjust(List<HeapNode> nodeList, int parent){while (2 * parent + 1 < nodeList.Count){//当前index节点的左孩子var left = 2 * parent + 1;//当前index节点的右孩子var right = left + 1;//parent子节点中最大的孩子节点,方便于parent进行比较//默认为left节点var max = left;//判断当前节点是否有右孩子if (right < nodeList.Count){//判断parent要比较的最大子节点max = nodeList[left].level < nodeList[right].level ? right : left;}//如果parent节点小于它的某个子节点的话,此时筛操作if (nodeList[parent].level < nodeList[max].level){//子节点和父节点进行交换操作var temp = nodeList[parent];nodeList[parent] = nodeList[max];nodeList[max] = temp;//继续进行更下一层的过滤parent = max;}else{break;}}}#endregion

最后我还扩展了一个弹出并下降节点优先级的方法,好了,这个方法大家自己琢磨琢磨,很有意思的,实际应用中使用到了,下面是完整代码的网盘链接:

链接:https://pan.baidu.com/s/15clOhAGOzz10HCEW0YqWKQ 提取码:z69b

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309187.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL9 查找除复旦大学的用户信息(数据库否定语句写法)

描述 题目&#xff1a;现在运营想要查看除复旦大学以外的所有用户明细&#xff0c;请你取出相应数据 示例&#xff1a;user_profile 根据输入&#xff0c;你的查询应返回以下结果&#xff1a; 示例1 输入&#xff1a; drop table if exists user_profile; CREATE TABLE use…

SQL10 用where过滤空值练习

描述 题目&#xff1a;现在运营想要对用户的年龄分布开展分析&#xff0c;在分析时想要剔除没有获取到年龄的用户&#xff0c;请你取出所有年龄值不为空的用户明细数据。 示例&#xff1a;user_profile 根据输入&#xff0c;你的 查询应返回以下结果&#xff1a; 示例1 输入…

数据结构与算法专题——第一题 Bitmap算法

在所有具有性能优化的数据结构中&#xff0c;我想大家使用最多的就是hash表&#xff0c;是的&#xff0c;在定位查找场景上具有O(1)的常量时间&#xff0c;多么的简洁优美&#xff0c;但是在特定的场合下&#xff1a;①&#xff1a;对10亿个不重复的整数进行排序。②&#xff1…

Java阻止继承(sealed,permits)

阻止继承 正常情况下&#xff0c;只要某个class没有final修饰符&#xff0c;那么任何类都可以从该class继承。 从Java 15开始&#xff0c;允许使用sealed修饰class&#xff0c;并通过permits明确写出能够从该class继承的子类名称。 例如&#xff0c;定义一个Shape类&#xf…

SQL15 查看学校名称中含北京的用户(通配符使用)

描述 题目&#xff1a;现在运营想查看所有大学中带有北京的用户的信息&#xff0c;请你取出相应数据。 示例&#xff1a;用户信息表&#xff1a;user_profile 根据示例&#xff0c;你的查询应返回如下结果&#xff1a; 示例1 输入&#xff1a; drop table if exists user_p…

Telegraf和Grafana监控多平台上的SQL Server

问题SQL Server在很多企业中部署在多个平台上(Windows,Linux和Container)&#xff0c;需要一种能支持多平台的解决方案用于收集和展示相关的监控指标。我选择企业中比较流行的监控展示工具Grafana和监控指标收集工具Telegraf进行实现。这也是为了方便与企业中已经在存在监控平台…

Java 12 switch表达式新特性(->,yield)

switch表达式 使用switch时&#xff0c;如果遗漏了break&#xff0c;就会造成严重的逻辑错误&#xff0c;而且不易在源代码中发现错误。从Java 12开始&#xff0c;switch语句升级为更简洁的表达式语法&#xff0c;使用类似模式匹配&#xff08;Pattern Matching&#xff09;的…

Java 实例 - 队列(Queue)用法

队列是一种特殊的线性表&#xff0c;它只允许在表的前端进行删除操作&#xff0c;而在表的后端进行插入操作。 LinkedList类实现了Queue接口&#xff0c;因此我们可以把LinkedList当成Queue来用。 以下实例演示了队列&#xff08;Queue&#xff09;的用法&#xff1a; import…

每日一练(第一天)

1、交换机本质上是一种网桥 &#xff08;是&#xff09;。 分析&#xff1a; 网桥&#xff08;Bridge)也称为桥接器&#xff0c;是连接两个局域网的存储转发设备&#xff0c;用它可以使完全具有相同或相似体系结构网络系统的连接&#xff0c;这样不但能扩展网络的距离或范围&a…

酸吗?28岁程序员财务自由宣布退休!

财务自由是我们这代人的共同追求&#xff0c;有程序员28岁就做到了。近期的一条新闻就直接刷屏了&#xff0c;28岁今日头条程序员手握上亿期权宣布退休&#xff0c;引发一片羡慕嫉妒恨。履历如下&#xff1a;2008-2012就读于暨南大学政治与行政管理专业&#xff0c;自学编程。2…

Java Stack 类

Java Stack 类 栈是Vector的一个子类&#xff0c;它实现了一个标准的后进先出的栈。 堆栈只定义了默认构造函数&#xff0c;用来创建一个空栈。 堆栈除了包括由Vector定义的所有方法&#xff0c;也定义了自己的一些方法。 Stack() 除了由Vector定义的所有方法&#xff0c;自…

nuget 是如何还原包的

nuget 是如何还原包的Intro一直以来从来都只是简单的用 nuget 包&#xff0c;最近想折腾一个东西&#xff0c;需要自己搞一个 nuget 包的解析&#xff0c;用户指定 nuget 包的名称和版本&#xff0c;然后去解析对应的 nuget 包并添加引用到项目&#xff0c; 于是就想搞明白 nug…

linux技术笔记(常用命令)持续更新中。。。

文章目录1、Linux 下解压 .zip 和 .rar 文件2、 [Mac 终端命令大全](https://www.jianshu.com/p/3291de46f3ff)3、Maven环境本地仓库目录阿里云仓库镜像系统环境变量mac 配置环境变量&#xff0c;退出终端失效的问题1、Linux 下解压 .zip 和 .rar 文件 解压 .zip zip -r file…

iMovie使用技巧

iMovie使用技巧 学习视频&#xff1a; 流程笔记&#xff1a; J、k、l浏览片段 1、i 设置出点 2、o设置入点 3、剪辑阶段可直接拖动片段&#xff0c;浏览阶段f设置为喜欢&#xff0c;有一条绿色的线 4、不喜欢的素材可直接按delete&#xff0c;标记为不喜欢&#xff0c;有一条红…

使用Azure AD B2C为ASP.NET Core 设置登录/注册

一&#xff0c;引言上次关于Azure AD B2C 讲到一些概念&#xff0c;有介绍到&#xff0c;Azure AD B2C 也是一种身份验证的解决方案&#xff0c;但是它运行客户使用其首选的社交&#xff0c;企业或者本地账户标识对应用程序和API进行单一登录访问。同样&#xff0c;Azure AD B2…

safari浏览器的使用tips

前言&#xff1a;最近毕设&#xff0c;原有Windows电脑太卡&#xff0c;再加上用mac习惯了&#xff0c;就买了mac笔记本&#xff0c;最后还是safari好用&#xff0c;那就整理下我在使用中好用的快捷键或者小tips 文章目录截图截图 全屏截图 shiftcommand3 safari界面浮窗 shif…

使用 Azure Function 定时启动云 VM

点击上方蓝字关注“汪宇杰博客”导语微软 Azure 平台的 VM 可以做到定时自动关机&#xff0c;然而只有 DevTest Lab 服务中的 VM 能够定时开机&#xff0c;普通用途的 VM 还没有上线这个功能。但是没关系&#xff0c;我们可以曲线救国&#xff0c;通过最新版的 Azure Function …

一个毕设的建成——记录下我毕设途中的《SOP》

文章目录记录过程中遇到解决的方法1、pom导入的包&#xff08;权限比较大&#xff09;记录过程中遇到解决的方法 https://blog.csdn.net/zeng_jun_yv/article/details/118892438 1、pom导入的包&#xff08;权限比较大&#xff09; <&#xff01;--https://mvnrepository…

文章目录 | .NET Core on K8s学习之旅 (更新至20200618)

.NET Core on K8s学习之旅更新记录&#xff1a;-- 20200511 增加Ingress & Nginx Ingress介绍-- 20200515 增加Ocelot API网关集成示例介绍-- 20200525 增加Ingress实现灰度发布示例介绍1关于这个系列文章自从2018年底离开工作了3年的M公司加入X公司之后&#xff0c;开始了…