Unity 3D常用的数据结构
目录
- 数组
- 使用场景
- ArrayList数组
- ArrayList的缺点
- List\<T\>数组
- List\<T\>有以下3点好处
- 链表
- 链表与数组的不同之处
- 链表的优势
- 数组和链表的应用场景
- LinkedList\<T\>
- C#中内置的双向链表LinkedList
- 使用场景
- 队列(Queue\<T\>)和栈(Stack\<T\>)
- queue队列
- 内部实现
- 栈
- 内部实现
- Hashtable哈希表
- 如何处理哈希冲突
- 避免哈希冲突
- 解决哈希冲突
- 开放寻址法的简单实现——线性探查(Linear Probing)
- 针对线性探查方式所存在的问题,一种改进的方式为二次探查(Quadratic Probing)
- 二度哈希
- 二度哈希的工作原理
- loadFactor
- Hashtable类的实例中添加新元素时,需要检查以保证元素与空间大小的比例不会超过最大比例。如果超过了,Hashtable类实例的空间将被扩充。空间扩充的步骤如下
- Dictionary\<K,T\>字典
- 冲突解决机制
- Dictionary<K,T>类的缺点
- 使用场景
数组
使用场景
元素的数量是固定的,并且需要使用下标时。
ArrayList数组
为了解决Array创建时必须指定长度,以及只能存放相同类型的缺点而推出的数据结构。
ArrayList的缺点
- ArrayList是类型不安全的。因为把不同的类型都当作Object来做处理,很有可能会在使用ArrayList时发生类型不匹配的情况。
- 数组存储值类型时并未发生装箱,但是ArrayList由于把所有类型都当作了Object,所以不可避免的是当插入值类型时会发生装箱操作,在索引取值时会发生拆箱操作。因此在频繁读写 ArrayList 时会产生额外的开销,导致性能下降。
List<T>数组
可以认为List<T> 类是 ArrayList 类的泛型等效类。
List<T>有以下3点好处
- 即确保了类型安全。因此List<T>是类型安全的。
- 取消了装箱和拆箱的操作,以及由于引入泛型而无需运行时类型检查。因此List<T>是高性能的。
- 融合了Array可以快速访问的优点,以及ArrayList长度可以灵活变化的优点。
链表
链表与数组的不同之处
数组中的内容在内存中是连续排列的,可以通过下标来访问。
链表中内容的顺序则是由各个对象的指针所决定的,这就决定了其内容的排列不一定是连续的,所以不能通过下标来访问。
链表的优势
使用链表最主要的优势就在于向链表中插入或删除节点时,无需考虑调整结构的容量。相反的对于数组来说容量始终是固定的,且数组中的内容在内存中是连续的。因此如果需要存放更多的数据,则面临着需要调整数组容量的现实,这就会引发新建数组、数据拷贝等一系列复杂且影响效率的操作。即使是List<T>类,虽然其对开发人员隐藏了容量调整的复杂性,但实质上性能的损耗是必须考虑的。
数组和链表的应用场景
数组适合数据的数量是有上限,且需要快速访问其元素内容的情况.
链表适合元素数量不固定且需要经常增删结点的情况。
LinkedList<T>
C#中内置的双向链表LinkedList
在Unity 3D开发过程中,由于C#已经为开发者封装了一个对应链表的类——LinkedList<T>类。因此可以很方便地通过LinkedList<T>来实现链表的功能。而和LinkedList<T>类相配套的,C#还提供了链表的结点类——LinkedListNode<T>类以用来代表链表中的结点,LinkedList<T>对象中的每个节点都属于LinkedListNode<T>类型。由于LinkedList<T>是双向链表,因此每个节点向前指向Next节点,向后指向Previous节点。
需要说明的一点是,LinkedList<T>类的插入和移除的运算复杂度都是O(1)。而由于该列表还维护内部计数,因此获取Count属性的运算复杂度也为 O(1)。
如何创建一个链表LinkedList<T>,以及最常见的几种操作。
- AddFirst,将一个新结点加入该链表的第一个结点的位置;
- RemoveFirst,将第一个结点移除;
- AddLast,将一个新节点加入该链表最后一个结点的位置;
- 以及在某个结点前后插入新的结点的AddBefore和AddAfter方法。
- 对链表中的结点类LinkedListNode的各种操作。
使用场景
元素需要能够在列表的两端添加时。否则使用List<T>。
队列(Queue<T>)和栈(Stack<T>)
queue队列
内部实现
在Queue<T>内部,有一个存放类型为T的对象的环形数组,并通过head 和tail变量来指向该数组的头和尾。当使用Enqueue方法将新的元素入列时,会判断队列的长度是否足够。若不足,则依据增长因子来增加容量,例如当为初始的2.0时,则队列容量增长2倍。
在默认情况下,Queue<T>的初始化容量是32,但是也可以通过构造函数指定容量。
元素的进出顺序是先进先出(FIFO)
栈
栈(Stack)又名堆栈,它和队列一样是一种运算受限的线性表。
其限制是仅允许在表的一端进行插入和删除的操作运算。这一端称为栈顶,相对的,把另一端称为栈底。
向一个栈插入新元素称为进栈、入栈或压栈。
一个栈删除元素称为出栈或退栈,它是把栈顶元素删除,使其相邻的元素成为新的栈顶元素。
元素的进出顺序是后进先出(LIFO)
内部实现
内部同样使用了数组来实现。内部结构可以通过一个垂直的数组来形象的表示。
Hashtable哈希表
哈希表(Hash Table,也叫散列表),是根据关键码/值(Key/value)而直接进行访问的数据结构。也就是说,它通过把关键码/值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫哈希函数或散列函数,存放记录的数组就叫哈希表。
如何处理哈希冲突
处理哈希冲突时,也有两种思路——避免和解决
- 冲突避免机制(Collision Avoidance)
- 冲突解决机制(Collision Resolution)
避免哈希冲突
避免哈希冲突的一个方法就是尽可能先择合适的哈希函数。
解决哈希冲突
- 将要插入的元素放到另一块空间中,因为相同的哈希位置已经被占用了。
- 开放寻址法(Open Addressing)
开放寻址法的简单实现——线性探查(Linear Probing)
- 当插入新的元素时,使用哈希函数在哈希表中定位元素位置。
- 检查哈希表中该位置是否已经存在元素。如果该位置内容为空,则插入并返回,否则进行步骤3的操作。
- 如果该位置为i,则检查i+1是否为空。如果已被占用,则检查i+2。依此类推,直到找到一个内容为空的位置。
线性探查(Linear Probing)方式虽然简单,但并不是解决冲突的最好策略,因为它会导致同类哈希的聚集(Primary Clustering)。这会导致搜索哈希表时,冲突依然存在。
针对线性探查方式所存在的问题,一种改进的方式为二次探查(Quadratic Probing)
即每次检查位置空间的步长为平方倍数。也就是说,如果位置s被占用,则首先检查s+12处,然后检查s-12、s+22、s-22、s+32…以此类推,而不是像线性探查那样以s+1、s+2…方式增长。
尽管如此,二次探查同样也会导致同类哈希聚集问题(Secondary Clustering)。
二度哈希
当在哈希表中添加或获取一个元素时,会发生哈希冲突。前面简单地介绍了两种冲突解决策略,即线性探查(Linear Probing)和二次探查(Quadratic Probing)。
二度哈希使用了Θ(m2)种探查序列,而线性探查(Linear Probing)和二次探查(QuadraticProbing)使用了Θ(m)种探查序列,因此二度哈希提供了更好的避免冲突的策略。
二度哈希的工作原理
有一个包含一组哈希函数H1…Hn的集合。当需要从哈希表中添加或获取元素时,首先使用哈希函数H1。如果导致冲突,则尝试使用H2。以此类推,直到Hn。所有的哈希函数都与H1十分相似,不同的是它们选用的乘法因子(multiplicative factor)。
当使用二度哈希时,重要的是在执行了hashsize次探查后,哈希表中的每一个位置都有且只有一次被访问到。也就是说,对于给定的key,对哈希表中的同一位置不会同时使用H1和H2 。在Hashtable类中使用二度哈希公式,其始终保持(1 +((GetHash(key) >> 5) + 1) %(hashsize - 1)
与hashsize
互为素数 (两数互为素数表示两者没有共同的质因子)
loadFactor
Hashtable类中还包含了一个私有成员变量loadFactor,loadFactor指定了哈希表中元素数量与位置(slot)数量之间的最大比例。 例如,如果loadFactor 等于0.5,则说明哈希表中只有一半的空间存放了元素值,其余一半都为空。
哈希表的构造函数允许用户指定loadFactor值,定义范围为0.1至1.0。然而不管提供的值是多少,范围都不会超过72%。即使传递的值为1.0,Hashtable类的loadFactor值还是0.72。微软官方认为loadFactor的最佳值为0.72,这平衡了速度与空间。因此,虽然默认的loadFactor为1.0,但系统内部却自动地将其改变为0.72。所以,建议使用缺省值1.0(但实际上是 0.72)。
Hashtable类的实例中添加新元素时,需要检查以保证元素与空间大小的比例不会超过最大比例。如果超过了,Hashtable类实例的空间将被扩充。空间扩充的步骤如下
- Hashtable类实例的位置空间几乎被翻倍。准确地说,位置空间值从当前的素数值增加到下一个最大的素数值。
- 因为二度哈希时,Hashtable类实例中的所有元素值将依赖于Hashtable类实例的位置空间值,所以Hashtable类实例中保存的所有值也需要重新二度哈希。
Dictionary<K,T>字典
Dictionary<K,T>使用强类型来限制Key和Item,当创建Dictionary<K,T>实例时,必须指定Key和Item的类型。
冲突解决机制
Dictionary<K,T>还采用了不同的冲突解决策略(Collision Resolution Strategy),这种技术称为链接技术(Chaining)。
链接技术(Chaining)将采用额外的数据结构来处理冲突。Dictionary<K,T>中的每个位置(slot)都映射到了一个链表。当冲突发生时,冲突的元素将被添加到桶(bucket)列表中。
Dictionary<K,T>类的缺点
它的缺点就是空间。以空间换时间,通过更多的内存开销来满足对速度的追求。在创建字典时,可以传入一个容量值,但实际使用的容量并非该值。而是使用不小于该值的最小质数作为它使用的实际容量,容量的最小值是 3。当有了实际容量后,并非直接实现索引,而是通过创建额外的两个数组来实现间接索引,即int[] buckets和Entry[] entries两个数组。因此面临的情况就是,即便新建了一个空的字典,那么伴随而来的是两个长度为3的数组。所以当处理的数据不多时,还是慎重使用字典为好,在很多情况下使用数组也是可以的。
使用场景
需要使用键值对(KeyValue)来快速添加和查找,并且元素没有特定的顺序时。
相关文章:
Unity 3D常用的数据结构
目录 数组使用场景 ArrayList数组ArrayList的缺点 List\<T\>数组List\<T\>有以下3点好处 链表链表与数组的不同之处链表的优势数组和链表的应用场景 LinkedList\<T\>C#中内置的双向链表LinkedList使用场景 队列(Queue\<T\>)和栈…...
h5唤起微信小程序
wx-open-launch-weapp 就用这个 开放标签属于自定义标签,Vue会给予未知标签的警告,可通过配置Vue.config.ignoredElements [wx-open-launch-weapp] 来忽略Vue对开放标签的检查。 sdk授权。 调试打开时iOS会弹窗 noPermissionJsApi: [],confi…...

面向对象(精髓)变继承关系为组和关系(_Decorator模式)
在软件开发中,设计模式是解决常见问题的可重用解决方案。在面向对象编程中,继承和组合是两种常用的代码复用方式。然而,随着软件需求的不断变化,我们需要更灵活的设计方式来应对不断变化的需求。在本文中,我们将讨论从…...

MES系统在智能生产中的重要作用
在未来智能制造的发展趋势中,制造执行系统(MES)作为关键技术和工具,扮演着至关重要的角色。随着科技的不断进步和制造业的数字化转型,MES的地位将愈发凸显,对于企业实现智能化生产、提高效率、降低成本具有…...
2024.3.13每日一题
LeetCode 最大二进制奇数 题目链接:2864. 最大二进制奇数 - 力扣(LeetCode) 题目描述 给你一个 二进制 字符串 s ,其中至少包含一个 1 。 你必须按某种方式 重新排列 字符串中的位,使得到的二进制数字是可以由该组…...

YOLOv5 | 涨点复现!YOLOv5添加BiFPN有效提升目标检测精度
目录 🚀🚀🚀订阅专栏,更新及时查看不迷路🚀🚀🚀 介绍: BiFPN 代码实现 ⭐欢迎大家订阅我的专栏一起学习⭐ 🚀🚀🚀订阅专栏,更新及…...
【Nut3】nuxt.config.ts项目nuxt配置文件介绍
简言 记录下nuxt3的nuxt.config.ts文件的介绍和使用。 Nuxt Configuration nuxt.config.ts Nuxt可以通过一个单独的nuxt.config文件进行简单配置。 配置文件创建 nuxt.config文件的扩展名可以是.js、.ts或.mjs。 然后默认导出全局函数defineNuxtConfig的返回值,…...
区块链技术的革命性影响
1. 区块链技术的基本原理: 区块链是一种去中心化的分布式数据库技术,通过不断增长的记录(块)构成一个链式结构。每个区块包含了交易数据的加密信息以及上一个区块的哈希值,从而形成了不可篡改的交易记录。这种去中心化…...

多线程(volatile)
volatile的功能 保证内存可见性禁止指令重排序 内存可见性 简单的理解 两(多)个线程同时针对一个变量进行操作, 一个线程读, 一个线程修改, 此时读到的值不一定是修改过后的值 即读线程没有感知到变量的变化 (其实是 编译器/JVM 对于代码在多线程情况下的优化进行了误判) 从 J…...

蓝桥杯 填空 卡片
蓝桥杯 填空题 卡片 解题思路: 我们只需要消耗完卡片的个数即可。 代码示例: #include<bits/stdc.h> using namespace std; int a[10]; bool isEnd(){for(int i0;i<10;i){if(a[i]-1)return false;}return true; } bool getN(int x){while(x){i…...

ELK介绍使用
文章目录 一、ELK介绍二、Elasticsearch1. ElasticSearch简介:2. Elasticsearch核心概念3. Elasticsearch安装4. Elasticsearch基本操作1. 字段类型介绍2. 索引3. 映射4. 文档 5. Elasticsearch 复杂查询 三、LogStash1. LogStash简介2. LogStash安装 四、kibana1. …...

【UE5】非持枪状态蹲姿移动的动画混合空间
项目资源文末百度网盘自取 在BlendSpace文件夹中单击右键选择动画(Animation)中的混合空间(Blend Space) ,选择SK_Female_Skeleton,命名为BS_NormalCrouch 打开BS_NormalCrouch 水平轴表示角色的方向,命名为Direction,方向的最…...
Windows C++ TCP开发(使用select函数以及设置非阻塞/Reuse属性)
1、select官方函数说明: 语法 C int WSAAPI select([in] int nfds,[in, out] fd_set *readfds,[in, out] fd_set *writefds,[in, out] fd_set *exceptfds,[in] const timeval *timeout );参数 [in] nfds 已忽略。 包含 nf…...

ARM TrustZone技术解析:构建嵌入式系统的安全扩展基石
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| 💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-LOdvohfCEnd8eKyd {font-family:"trebuchet ms",verdana,arial,sans-serif;f…...

初识Python语言-课堂练习【pyhton123题库】
初识Python语言-课堂练习【pyhton123题库】 一、单项选择题 1、Guido van Rossum正式对外发布Python版本的年份是: A 2008B 1998C 1991D 2002 【答案】C 【解析】暂无解析2、下面不是Python语言特点的是:…...

chrome高内存占用问题
chrome号称内存杀手不是盖的,不设设置的话,经常被它内存耗尽死机是常事。以下自用方法 1 自带的memory saver chrome://settings/performance PerformanceMemory Saver When on, Chromium frees up memory from inactive tabs. This gives active tab…...

【C语言】文件操作篇-----程序文件和数据文件,文件的打开和关闭,二进制文件和文本文件,fopen,fclose【图文详解】
欢迎来CILMY23的博客喔,本篇为【C语言】文件操作篇-----程序文件和数据文件,文件的打开和关闭,二进制文件和文本文件【图文详解】,感谢观看,支持的可以给个一键三连,点赞关注收藏。 前言 在了解完动态内存管…...
知识碎片收集
目录 1. 如何计算两点经纬度之间的距离2. 加权随机采样3.什么时LLDB和GDB 1. 如何计算两点经纬度之间的距离 1.知乎-如何计算两点经纬度间距离 2.根据两点经纬度坐标计算距离 3.根据经纬度计算两点之间的距离的公式推导过程以及google.maps的测距函数 4.根据经纬度点计算经…...

不可不知!用例图的绘制与应用全指南深度解析
在软件开发领域中,用例图是一种强大的工具,用于描述系统的功能需求以及系统与外部实体之间的交互。无论是在需求分析阶段还是在系统设计过程中,用例图都扮演着至关重要的角色。本文将全面介绍用例图的绘制方法和其在软件开发中的应用…...

【数据结构七】堆与PriorityQueue详解
堆 在Java中有一种数据结构基于队列,并保证操作的数据带有优先级,该数据结构应该提供了两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue)。它的底层使用了堆这种数据结…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...

毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...

sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑
精益数据分析(98/126):电商转化率优化与网站性能的底层逻辑 在电子商务领域,转化率与网站性能是决定商业成败的核心指标。今天,我们将深入解析不同类型电商平台的转化率基准,探讨页面加载速度对用户行为的…...