基于C#实现优先队列

一、堆结构

1.1性质

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

1.2用途

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

1.3实现

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

 /// <summary>/// 定义一个数组来存放节点/// </summary>private List<HeapNode> nodeList = new List<HeapNode>();#region 堆节点定义/// <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() { }}#endregion

<2> 入队操作
入队操作时我们要注意几个问题:
①:完全二叉树的构建操作是“从上到下,从左到右”的形式,所以入队的节点是放在数组的最后,也就是树中叶子层的有序最右边空位。
②:当节点插入到最后时,有可能破坏了堆的性质,此时我们要进行“上滤操作”,当然时间复杂度为 O(lgN)。
image.png
当我将节点“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> 出队操作
从图中我们可以看出,优先级最大的节点会在一阵痉挛后上升到堆顶,出队操作时,我们采取的方案是:弹出堆顶元素,然后将叶子层中的最右子节点赋给堆顶,同样这时也会可能存在破坏堆的性质,最后我们要被迫进行下滤操作。
image.png
我图中可以看出:首先将堆顶 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

image.png

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

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

相关文章

Doris动态分区(十四)

动态分区是在 Doris 0.12 版本中引入的新功能。旨在对表级别的分区实现生命周期管理&#xff08;TTL&#xff09;&#xff0c;减少用户的使用负担。 目前实现了动态添加分区及动态删除分区的功能。动态分区只支持 Range 分区。 原理 在某些使用场景下&#xff0c;用户会将表…

【中间件】服务化中间件理论intro

中间件middleware 内容管理 intro服务化middleware架构注册中心intro服务治理系统intro 本文主要intro服务化中间件的探讨 去年cfeng写了一篇博客走马观花般阐述了Spring Cloud下面的各种中间件&#xff0c;连深入使用都谈不上&#xff0c;只能说intro&#xff0c;在实际work中…

LabVIEW中将SMU信号连接到PXI背板触发线

LabVIEW中将SMU信号连接到PXI背板触发线 本文介绍如何将信号从PXI&#xff08;e&#xff09;SMU卡路由到PXI&#xff08;e&#xff09;机箱上的背板触发线。该过程涉及使用NI-DCPowerVI将SMU信号导出到PXI_TRIG线上。 在继续操作之前&#xff0c;请确保在开发PC上安装了兼容版…

python二叉树链树_树的链式存储结构

二叉链树是一种树状数据结构&#xff0c;其中每个节点最多有两个子节点&#xff0c;分别称为左子节点和右子节点。每个节点包含一个数据元素和指向其左右子节点的指针。二叉链树可以是空树&#xff0c;也可以是具有以下特点的非空树&#xff1a; 1. 每个节点最多有两个子节点。…

minio集群部署(k8s内)

一、前言 minio的部署有几种方式&#xff0c;分别是单节点单磁盘&#xff0c;单节点多磁盘&#xff0c;多节点多磁盘三种方式&#xff0c;本次部署使用多节点多磁盘的方式进行部署&#xff0c;minio集群多节点部署最低要求需要4个节点&#xff0c;集群扩容时也是要求扩容的节点…

【腾讯云云上实验室-向量数据库】腾讯云VectorDB:深度学习场景下的新一代数据存储方案

引言 ​  在深度学习领域的实践中&#xff0c;一般会涉及到向量化处理的数据&#xff0c;如图像、文本、音频等&#xff0c;这些数据的存储和检索对于许多深度学习任务至关重要。传统的关系型数据库和NoSQL数据库在存储和检索这类大规模向量数据时&#xff0c;通常不能满足高…

shell 条件语句

目录 测试 test测试文件的表达式 是否成立 格式 选项 比较整数数值 格式 选项 字符串比较 常用的测试操作符 格式 逻辑测试 格式 且 &#xff08;全真才为真&#xff09; 或 &#xff08;一真即为真&#xff09; 常见条件 双中括号 [[ expression ]] 用法 &…

DataFunSummit:2023年OLAP引擎架构峰会-核心PPT资料下载

一、峰会简介 OLAP技术是当前大数据领域的热门方向&#xff0c;该领域在各个行业都有广泛的使用场景&#xff0c;对OLAP引擎的功能有丰富多样的需求。同时&#xff0c;在性能、稳定性和成本方面&#xff0c;也有诸多挑战。目前&#xff0c;OLAP技术没有形成统一的事实标准&…

全局定制序列化

作用:将返回实体类中的属性如果为null 变成"" package com.example.micrweb.config;import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.f…

结构体打印

打印输出 通过注解来派生Debug trait&#xff0c;才可以通过println!进行打印。默认的占位符是{}&#xff0c;底层是按照std::fmt::Display具体实现进行格式化输出。 {}、{:?}、{#?}是格式化的几种形式&#xff0c;{#?}是更加易读的JSON话格式。 方法 结构体声明方法&…

随机微分方程的MATLAB数值求解

dt0.01; tout200; %总时间为2 xzeros(1,tout); x(1)0.5; %初始位置 mu0.2; sigma1; Wtsqrt(dt)*randn(1,tout); %产生随机序列Wt for t1:tout-1x(t1)x(t)mu*x(t)*dtsigma*x(t)*Wt(t); end t11:10:tout; %对原时间序列进行抽样 xtzeros(1,length(t1)); i1; for tt1xt(i)0.5*exp(…

Missing file libarclite_iphoneos.a 问题解决方案

问题 在Xcode 运行项目会报以下错误 File not found: /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a解决方案 打开URL https://github.com/kamyarelyasi/Libarclite-Files &#xff0c;下载liba…