【C# 数据结构】Heap 堆

【C# 数据结构】Heap 堆

  • 先看看C#中有那些常用的结构
  • 堆的介绍
    • 完全二叉树
    • 最大堆
  • Heap对类进行排序
      • 实现 `IComparable<T>` 接口
    • 对CompareTo的一点解释
  • 参考资料

先看看C#中有那些常用的结构

作为 数据结构系类文章 的开篇文章,我们先了解一下C# 有哪些常用的数据结构
C# 是一种通用、面向对象的编程语言,它提供了许多常用的数据结构,以便在开发过程中高效地存储和操作数据。以下是一些在 C# 中常用的数据结构:

  1. 数组 (Array):
    数组是一个固定大小的、相同类型元素的集合。使用索引来访问数组中的元素。

  2. 列表 (List):
    列表是一个动态大小的集合,可以根据需要自动增长或缩小。List 是泛型类,T 表示可以存储的元素类型。

  3. 链表 (LinkedList):
    链表是一种数据结构,其中的元素按节点 (Node) 连接在一起,每个节点包含一个数据元素和一个指向下一个节点的引用。

  4. 栈 (Stack):
    栈是一种后进先出 (Last-In-First-Out, LIFO) 的数据结构,只允许在顶部插入和删除元素。

  5. 队列 (Queue):
    队列是一种先进先出 (First-In-First-Out, FIFO) 的数据结构,允许在一端插入元素,在另一端删除元素。

  6. 字典 (Dictionary):
    字典是一种键值对 (Key-Value) 映射的集合,允许通过键来快速查找和访问值。

  7. 散列表 (HashSet, Hashtable):
    散列表是一种根据键快速查找值的数据结构。HashSet 是一个泛型类,而 Hashtable 是非泛型的旧式实现。

  8. 堆 (Heap):
    堆是一种特殊的树状数据结构,其中的每个节点的值都大于或小于其子节点的值。常用于优先队列等场景。

  9. 树 (Tree):
    树是一种分层数据结构,其中的节点以层次结构进行组织。常见的树包括二叉树、二叉搜索树等。

  10. 图 (Graph):
    图是一组节点和边的集合,用于表示各种复杂关系。常见的图算法包括深度优先搜索和广度优先搜索。

ps: 我们经常说堆栈堆栈,其实这样一看发现堆和栈的数据结构是完全不同的。

堆的介绍

完全二叉树

堆首先是个树状的结构,而且是个完全二叉树!什么是完全二叉树?

完全二叉树:二叉树除了最后一层节点外,其他层的节点个数必须是最大值,如果最后一层没有达到最大节点,则所有的节点必须偏向左边。

二叉堆
如何理解:其他层的节点个数必须是最大值?
就是第一层 一个节点,第二层 两个节点 第三层 四个节点,以此类推。
不过最后一层不要求节点个数是最大值。(最后一层没有达到最大节点,则所有的节点必须偏向左边)

那这个完全二叉树的定义有啥用了,为啥搞这么多规矩出来?
那是因为完全二叉树这样个树的结构,是可以通过数值存储的!(因为其节点的位置在数组中的索引之间有一种固定的关系)
数组和完全二叉树
前提:数据的0号地址不使用,从1开始使用。
如果将完全二叉树从上到下、从左到右依次编号,那么节点 i 的左子节点索引为 2i,右子节点索引为 2i+1,父节点索引为 i/2(注意这里除法是计算机里整除的意思)

当然二叉树还要其他特点这里了解即可:

  1. 完美填充:完全二叉树是按照从左到右的顺序填充节点的,除了最后一层外,其他层的节点都是满的(即每个节点都有两个子节点)。最后一层的节点从左到右填充,可能是满的,也可能是部分填充,但是最后一层的节点一定是从左到右依次填充的,不会有空洞。

  2. 叶节点:所有叶节点都集中在最后一层或者倒数第二层。如果最后一层的叶节点没有填满,则它们一定是从左到右依次连续排列的。

  3. 层数:完全二叉树的层数为 h,从根节点到倒数第二层都是满的,最后一层可能不满。因此,节点总数 N 满足 N = 2^h - 1 + 最后一层节点数。

  4. 高度平衡:由于完全二叉树的特点,其左右子树的高度差不会超过 1,因此是一个高度平衡的二叉树。

最大堆

首先最大堆,必须是完全二叉树
每一个节点可以有两个子节点。任何一个节点都不不大于他的父节点
那么最大堆,树顶的位置是最大的元素
有最大堆就有最小堆:
最小堆:树顶的位置是最小的元素(堆中某个节点的值总是不小于其父节点的值)

C# 中的 Heap 实际上是最小堆(Min Heap)的实现,其中最小的元素总是位于堆的顶部。

在 C# 中,可以使用 System.Collections.Generic 命名空间中的 Heap 数据结构来实现堆(Heap)。Heap 通常用于实现优先队列等场景,其中每个元素都有一个优先级(或者键值),并且可以根据优先级高低进行插入和删除操作。

下面是如何使用 Heap 数据结构的基本步骤:

Step 1: 导入命名空间
首先,在代码文件中导入 System.Collections.Generic 命名空间,以便可以使用 Heap 类。

using System.Collections.Generic;

Step 2: 创建 Heap
使用 Heap 类创建一个堆对象。Heap 类是一个泛型类,你需要指定元素的类型。以下是一个示例创建最小堆的代码:

Heap<int> minHeap = new Heap<int>();

Step 3: 插入元素
使用 Insert 方法将元素插入堆中。插入元素后,堆会自动调整,以确保最小元素位于堆的顶部。

minHeap.Insert(10);
minHeap.Insert(5);
minHeap.Insert(15);
minHeap.Insert(3);
// 此时堆为:3 5 15 10

Step 4: 获取堆顶元素
使用 Peek 方法获取堆顶(最小)元素,但不删除它。

int minValue = minHeap.Peek();
// minValue 等于 3
// 此时堆仍为:3 5 15 10

Step 5: 弹出堆顶元素
使用 ExtractMin 方法弹出堆顶元素(即删除堆顶最小元素),并返回该元素的值。

int minValue = minHeap.ExtractMin();
// minValue 等于 3,同时堆变为:5 10 15

看到这里我们知道堆的作用其实就是优先级排序,比如计算机任务,每个任务都会有一个优先级,优先级高的任务被先处理,而且随时还可能来新的任务。 那我们为何要使用对进行排序呢?
那是因为每次来新任务时,就需要重新排序,如果是普通的排序,计算量是非常大的:
对比
复杂度对比
也就是说堆在实现优先级排序的时候是最合适的。

至于如何自己写代码实现一个堆,这里就不说了,继续介绍实际中会直接用到的。
现在假设我有一个类,而不是int这样的数组,我们怎么用堆排序呢?

Heap对类进行排序

当你有一个自定义的类,想要在 Heap 中根据类的某个属性来表示优先级时,你可以通过实现 IComparable<T> 接口或者自定义比较器来实现。

假设你有一个名为 MyClass 的类,其中包含一个整数属性 Priority 用于表示优先级,那么你可以按照以下两种方法之一来使用 Heap<MyClass> 并根据 Priority 属性来表示优先级:

实现 IComparable<T> 接口

MyClass 类实现 IComparable<T> 接口,并在 CompareTo 方法中定义对象之间的优先级比较逻辑。

using System;
using System.Collections.Generic;

public class MyClass : IComparable<MyClass>
{
    public int Priority { get; set; }
    public string Data { get; set; }

    // 实现 IComparable<T> 接口中的 CompareTo 方法
    public int CompareTo(MyClass other)
    {
        return Priority.CompareTo(other.Priority);
    }
}

// 创建最小堆,根据 MyClass 的优先级属性进行比较
Heap<MyClass> minHeap = new Heap<MyClass>();

// 添加 MyClass 对象到最小堆
minHeap.Insert(new MyClass { Priority = 10, Data = "Value1" });
minHeap.Insert(new MyClass { Priority = 5, Data = "Value2" });
minHeap.Insert(new MyClass { Priority = 15, Data = "Value3" });
minHeap.Insert(new MyClass { Priority = 3, Data = "Value4" });

// 弹出堆顶元素(优先级最小的对象)
while (minHeap.Count > 0)
{
    MyClass minPriorityObj = minHeap.ExtractMin();
    Console.WriteLine($"Priority: {minPriorityObj.Priority}, Value: {minPriorityObj.Data}");
}

这种方法都允许你在 Heap<MyClass> 中根据 Priority 属性来表示对象的优先级,并按优先级顺序插入和弹出对象。

对CompareTo的一点解释

有些童鞋对这里可能有的不明白,这里稍微解释一下

public int CompareTo(MyClass other)
{
    return Priority.CompareTo(other.Priority);
}

首先,C# 有跟多类实现了 实现 IComparable 接口中的 CompareTo 方法
用于比较对象之间的大小关系。这些类实现了 IComparable<T> 接口,以允许在容器中进行自定义排序。以下是一些常见的实现了 CompareTo 方法的类:

  1. Int32Int64SingleDoubleDecimal 等数值类型:这些数值类型都实现了 IComparable<T> 接口,使得它们可以通过 CompareTo 方法进行比较。

  2. DateTime 类:DateTime 类也实现了 IComparable<T> 接口,因此你可以使用 CompareTo 方法来比较日期和时间的大小。

  3. String 类:String 类实现了 IComparable<T> 接口,允许你比较字符串的大小关系。它使用基于 Unicode 编码的排序规则。

  4. TimeSpan 类:TimeSpan 类实现了 IComparable<T> 接口,允许你比较时间间隔的大小关系。

  5. Enum 枚举类型:枚举类型实现了 IComparable<T> 接口,使得枚举值之间可以通过 CompareTo 方法进行比较。

  6. Version 类:Version 类用于表示软件版本号,它实现了 IComparable<T> 接口,允许你比较软件版本的大小关系。

x.Priority.CompareTo(y.Priority) 是一个比较表达式,用于比较两个对象 xyPriority 属性的值。它会返回一个整数,指示这两个值之间的关系。

具体含义如下:

  • 如果 x.Priority 小于 y.Priority,则表达式返回负数(通常为-1)。
  • 如果 x.Priority 等于 y.Priority,则表达式返回零。
  • 如果 x.Priority 大于 y.Priority,则表达式返回正数(通常为1)。

这个返回值在使用自定义比较器或实现 IComparable<T> 接口时非常重要,因为它将用于决定如何排序或比较两个对象。根据返回值的正负,容器(如 HeapList 等)会根据你定义的比较逻辑来确定对象的排序顺序。

例如,在上述代码中,我们使用了这个比较表达式来定义 MyClass 对象之间的优先级比较逻辑。在最小堆中,这个比较表达式的结果将决定 MyClass 对象的排序顺序,使得具有较小 Priority 属性值的对象排在堆顶,而具有较大 Priority 属性值的对象排在堆底。

所以,返回值的含义非常简单,它指示了两个对象之间的大小关系,用于实现排序和比较。

参考资料

https://coding.imooc.com/class/71.html

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【防火墙】iptables防火墙(一)

防火墙具有隔离功能 主要部署在网络边缘或者主机边缘&#xff0c;防火墙的主要作用是决定哪些数据可以被外网访问&#xff0c;哪些数据可以进入内网访问 网络层&#xff08;路由器&#xff09;&#xff1a;数据的转发 安全技术 1.入侵监测系统&#xff1a;在检测到威胁&…

城市气象数据可视化:洞察气候变化,构建智慧城市

随着城市化进程的加速&#xff0c;城市气象数据的采集和分析变得越来越重要。气象数据不仅影响着人们的生活和出行&#xff0c;还与城市的发展和规划息息相关。在数字化时代&#xff0c;如何将城市中各个气象数据进行可视化&#xff0c;让复杂的数据变得简单易懂&#xff0c;成…

全国大学生数据统计与分析竞赛2021年【本科组】-B题:用户消费行为价值分析

目录 摘 要 1 任务背景与重述 1.1 任务背景 1.2 任务重述 2 任务分析 3 数据假设 4 任务求解 4.1 任务一&#xff1a;数据预处理 4.1.1 数据清洗 4.1.2 数据集成 4.1.3 数据变换 4.2 任务二&#xff1a;对用户城市分布情况与分布情况可视化分析 4.2.1 城市分布情况可视化分析 4…

微信小程序客服系统-对接消息推送-对接模板订阅消息-嵌入webview客服链接

想要给自己的小程序增加客服系统功能 小程序客服对接导自己的系统等需求&#xff0c;可以参照我开发的客服系统&#xff0c;实现私有化部署搭建对接的微信小程序 小程序消息推送对接 首先登录小程序后台在小程序后台>开发管理>开发设置>服务器域名部分&#xff0c;配置…

使用TensorFlow训练深度学习模型实战(下)

大家好&#xff0c;本文接TensorFlow训练深度学习模型的上半部分继续进行讲述&#xff0c;下面将介绍有关定义深度学习模型、训练模型和评估模型的内容。 定义深度学习模型 数据准备完成后&#xff0c;下一步是使用TensorFlow搭建神经网络模型&#xff0c;搭建模型有两个选项…

Java-运算符

目录 一、什么是运算符 二、算术运算符 1.基本四则运算符&#xff1a;加减乘除&#xff08;、-、*、/、%&#xff09; 2.增量运算符&#xff08;、-、*、%&#xff09; 3.自增、自减运算符&#xff08;、--&#xff09; 三、关系运算符 四、逻辑运算符 1.逻辑与 && …

Vue前端渲染blob二进制对象图片的方法

近期做开发&#xff0c;联调接口。接口返回的是一张图片&#xff0c;是对二进制图片处理并渲染&#xff0c;特此记录一下。 本文章是转载文章&#xff0c;原文章&#xff1a;Vue前端处理blob二进制对象图片的方法 接口response是下图 显然&#xff0c;获取到的是一堆乱码&…

【Docker】安全及日志管理

目录 一、Docker 安全及日志管理1.1 Docker 容器与虚拟机的区别1. 隔离与共享2. 性能与损耗 1.2Docker 存在的安全问题1.Docker 自身漏洞2.Docker 源码问题 1.3 Docker 架构缺陷与安全机制1. 容器之间的局域网攻击2. DDoS 攻击耗尽资源3. 有漏洞的系统调用4. 共享root用户权限 …

网安第二天笔记

ssh 22端口 账号密码登陆、证书登录 smtp 25端口 邮件协议 DNS 53 DHCP 67 68端口 四个包 1.DHCP服务器&#xff1a;服务器管理IP地址池和配置参数 2.客户端请求&#xff1a;发送DHCP广播请求&#xff0c;discover消息 3.DHCP服务器回应&#xff1a;收到discover会回复offer…

PostMan+Jmeter+QTP工具介绍及安装

目录 一、PostMan介绍​编辑 二、下载安装 三、Postman与Jmeter的区别 一、开发语言区别&#xff1a; 二、使用范围区别&#xff1a; 三、使用区别&#xff1a; 四、Jmeter安装 附一个详细的Jmeter按照新手使用教程&#xff0c;感谢作者&#xff0c;亲测有效。 五、Jme…

Linux_CentOS_7.9部署Docker以及镜像加速配置等实操验证全过程手册

前言&#xff1a;实操之前大家应该熟悉一个新的名词DevOps 俗称开发即运维、新一代开发工程师&#xff08;Development和Operations的组合词&#xff09;是一组过程、方法与系统的统称&#xff0c;用于促进开发&#xff08;应用程序/软件工程&#xff09;、技术运营和质量保障&…

Angular:动态依赖注入和静态依赖注入

问题描述&#xff1a; 自己写的服务依赖注入到组件时候是直接在构造器内初始化的。 直到看见代码中某大哥写的 private injector: Injector 动态依赖注入和静态依赖注入 在 Angular 中&#xff0c;使用构造函数注入的方式将服务注入到组件中是一种静态依赖注入的方式。这种方…

Python显示循环代码的进度条

目录 1. tqdm库 2. alive_progress库 3. progressbar库 1. tqdm库 tqdm是一个快速&#xff0c;可扩展的Python进度条&#xff0c;可以在Python长循环中添加一个进度提示信息 import time from tqdm import trangefor i in trange(100):# do somethingtime.sleep(0.5) 2. a…

微服务——Nacos配置管理

目录 Nacos配置管理——实现配置管理 配置管理实践 Nacos配置管理——微服务配置拉取 Nacos配置管理——配置热更新 方式一: ​编辑 方式二(推荐方式): Nacos配置管理——多环境配置共享 优先级问题 Nacos配置管理——nacos集群搭建 总结​编辑 Nacos配置管理——实现配置管…

【ADS】导入CMOS衬底文件+使用coilsys生成电感

新建工程经常忘记怎么操作&#xff0c;简记防遗忘。 操作步骤 1.unzip file2.原理图仿真3.Layout加载衬底文件4.使用coilsys生成电感 1.unzip file designKits-》unzip&#xff0c;选择对应库的压缩包&#xff0c;我这里是&#xff08;TSMC_CRN65GP_v2.zip&#xff09;。 为了…

BHQ 1Mal,BHQ-1 Maleimide,BHQ1马来酰亚胺,黑洞猝灭剂

资料编辑|陕西新研博美生物科技有限公司小编MISSwu​ PART1----产品描述&#xff1a; BHQ-1 Maleimide黑洞猝灭剂-1(BHQ-1)被归类为暗猝灭剂&#xff0c;该淬灭剂能够将一定距离内荧光基团发出的光全部吸收&#xff0c;实现对荧光信号的淬灭&#xff0c;所以可得到更强的特异性…

【App管理04-Bug修正 Objective-C语言】

一、咱们刚才已经把这个给大家做完了吧 1.这个Label怎么显示到上面去了, 我们现在是把它加到我们的控制器的View里面吧 我们看一下这个坐标是怎么算的,来,我们找一个坐标, 咱们的坐标,是不是用这个View的frame,减的吧 来,咱们在这里,输出一下这个Frame,看一下吧 在…

2023年第三届能源、电力与电气工程国际会议 (CoEEPE 2023)

会议简介 Brief Introduction 2023年第三届能源、电力与电气工程国际会议(CoEEPE 2023) 会议时间&#xff1a;2023年11月22日-24日 召开地点&#xff1a;澳大利亚墨尔本 大会官网&#xff1a;www.coeepe.org 2023年第三届能源、电力与电气工程国际会议(CoEEPE 2023)由安徽大学、…

Linux:Linux的发展史和作用有哪些?

文章目录 Linux是什么&#xff1f;Linux的开源特征为什么要学习Linux&#xff1f;Linux的应用场景有哪些&#xff1f; Linux是什么&#xff1f; 简单来说&#xff0c;Linux就是操作系统&#xff0c;它和Windows等软件一样&#xff0c;都只是操作系统&#xff0c;并无区别 Linu…

如何将ubuntu LTS升级为Pro

LTS支持周期是5年&#xff1b; Pro支持周期是10年。 Ubuntu Pro专业版笔记 步骤&#xff1a; 打开“软件和更新” 可以看到最右侧的标签是Ubuntu Pro。 在没有升级之前&#xff0c;如果使用下面两步&#xff1a; sudo apt updatesudo apt upgrade 出现如下提示&#xff…