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点好处
  1. 即确保了类型安全。因此List<T>是类型安全的。
  2. 取消了装箱和拆箱的操作,以及由于引入泛型而无需运行时类型检查。因此List<T>是高性能的。
  3. 融合了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)
避免哈希冲突

避免哈希冲突的一个方法就是尽可能先择合适的哈希函数。

解决哈希冲突
  1. 将要插入的元素放到另一块空间中,因为相同的哈希位置已经被占用了。
  2. 开放寻址法(Open Addressing)
开放寻址法的简单实现——线性探查(Linear Probing)
  1. 当插入新的元素时,使用哈希函数在哈希表中定位元素位置。
  2. 检查哈希表中该位置是否已经存在元素。如果该位置内容为空,则插入并返回,否则进行步骤3的操作。
  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类实例的空间将被扩充。空间扩充的步骤如下
  1. Hashtable类实例的位置空间几乎被翻倍。准确地说,位置空间值从当前的素数值增加到下一个最大的素数值。
  2. 因为二度哈希时,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)来快速添加和查找,并且元素没有特定的顺序时。

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

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

相关文章

裸机编程的几种模式、架构与缺陷。

大多数嵌入式的初学者都是从单片机裸机编程开始的&#xff0c;对于初学者来说&#xff0c;裸机编程更加直观、简单&#xff0c;代码所见及所得&#xff0c;调试也非常方便&#xff0c;区别于使用操作系统需要先了解大量的操作系统基础知识&#xff0c;调度的基本常识&#xff0…

Redis及其数据类型和常用命令(一)

Redis 非关系型数据库&#xff0c;不需要使用sql语句对数据库进行操作&#xff0c;而是使用命令进行操作&#xff0c;在数据库存储时使用键值对进行存储&#xff0c;应用场景广泛。 一般关系型数据库&#xff08;使用sql语句进行操作的数据库&#xff09;和非关系型数据库可以…

Docker基础介绍

Docker是一种容器化平台&#xff0c;它可以轻松地封装、分发和运行应用程序和服务。 Docker的基本概念包括&#xff1a; 容器&#xff1a;一个独立运行的、可移植的软件包&#xff0c;包含应用程序、运行环境和依赖项。容器可以在不同的环境中运行&#xff0c;而不受环境差异的…

每日一题 — 四数之和

18. 四数之和 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 双指针思想&#xff0c;转换成三数之和&#xff0c;在转换成二数之和先排序&#xff0c;固定一个数a&#xff0c;转换成三数之和再固定一个数b&#xff0c;转换成二数之和再注意不漏和去重 代码&#…

详细说说JVM的class文件(一)

介绍 class虚拟机实现可以从文件系统(环境变量)读取也可以从JAR(或者ZIP)包提取&#xff0c;也可以从网上下载&#xff0c;从数据库加载&#xff0c;甚至在运行中直接生成class文件。 文件由8位字节流组成。16位和32位的数量分别通过读入两个和四个连续的8位字节来构造。多字…

[LeetCode][426]【学习日记】将二叉搜索树转化为排序的双向链表——前驱节点pre 和 当前节点cur 的使用

题目 426. 将二叉搜索树转化为排序的双向链表 将一个 二叉搜索树 就地转化为一个 已排序的双向循环链表 。 对于双向循环列表&#xff0c;你可以将左右孩子指针作为双向循环链表的前驱和后继指针&#xff0c;第一个节点的前驱是最后一个节点&#xff0c;最后一个节点的后继是第…

读算法的陷阱:超级平台、算法垄断与场景欺骗笔记07_价格歧视

1. 行为歧视 1.1. 单个企业通过使用数据驱动的算法&#xff0c;从而更好地实现锁定客户、开展个性化营销与定价的目的 1.2. 市场环境再次发生了变化 1.2.1. 在共谋场景中&#xff0c;定价算法提高了企业经营者在销量数据上的透明性&#xf…

通讯协议制定之常见问题、注意事项总结

文章目录 通讯协议制定之常见问题、注意事项总结1. 通讯协议制定介绍小结2. 常见的问题及注意事项总结2.1 3次握手2.2 心跳检测2.3 ACK回复及重发机制2.4 通信协议版本匹配2.5 校验的重要性2.6 最大数据传输长度2.7 大小端问题2.8 通信负载能力2.9 压力测试的重要性 通讯协议制…

【Java从入门到精通】Java异常处理

异常是程序中的一些错误&#xff0c;但并不是所有的错误都是异常&#xff0c;并且错误有时候是可以避免的。 比如说&#xff0c;你的代码少了一个分号&#xff0c;那么运行出来结果是提示是错误 java.lang.Error&#xff1b;如果你用System.out.println(11/0)&#xff0c;那么…

Java并发编程: AQS

文章目录 一、前置知识二、什么是AQS三、使用AQS框架的锁和同步器1、ReentrantLock2、ReentrantReadWriteLock3、CountDownLatch4、CyclicBarrier5、Semaphore&#xff1a;信号量 四、锁和同步器的关系1、锁&#xff1a;面向锁的使用者2、同步器&#xff1a;面向锁的实现者 五、…

四川易点慧电子商务有限公司抖音小店安全正规

在如今网络购物日益普及的时代&#xff0c;消费者对于购物平台的选择越来越挑剔。四川易点慧电子商务有限公司抖音小店以其安全正规的经营模式&#xff0c;赢得了广大消费者的信赖和好评。本文将为您详细介绍四川易点慧电子商务有限公司抖音小店的优势和特点&#xff0c;让您在…

Vue3全家桶 - Vue3 - 【2】声明响应式数据(ref + reactive + toRef + toRefs)

声明响应式数据 一、 组合式API 1.1 ref() ref() 函数&#xff0c;可以创建 任何数据类型 的 响应式数据&#xff1b;&#x1f53a;注意&#xff1a; 当值为 对象类型 时&#xff0c;会用 reactive() 自动转换它的 .value&#xff1b; ref 函数的内部实现依赖于 reactive 函…

代码随想录训练营第六天|242. 有效的字母异位词

242. 有效的字母异位词 已解答 简单 相关标签 相关企业 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 示例 1: 输入: s "anagram&q…

【AI】如何创建自己的自定义ChatGPT

如何创建自己的自定义ChatGPT 目录 如何创建自己的自定义ChatGPT大型语言模型(LLM)GPT模型ChatGPTOpenAI APILlamaIndexLangChain参考推荐超级课程: Docker快速入门到精通Kubernetes入门到大师通关课本文将记录如何使用OpenAI GPT-3.5模型、LlamaIndex和LangChain创建自己的…

Sqoop 学习

参考视频 大数据Sqoop教程丨从零开始讲解大数据业务及数据采集和迁移需求_哔哩哔哩_bilibili 介绍 Sqoop是Hadoop生态体系和RDBMS&#xff08;关系型数据库&#xff09;体系之间传送数据的一种工具 Hadop生态系统&#xff1a;HDFS&#xff0c;Hbase&#xff0c;Hive等 RDBMS包…

java-ssm-基于jsp商场停车服务管理信息系统

java-ssm-基于jsp商场停车服务管理信息系统

为HTTP的2024端口设置重定向

为HTTP的2024端口设置重定向 server { listen 80:2024; server_name www.test.com; # 将HTTP的2024端口请求重定向到对应的HTTPS端口 return 301 https://$host:2024$request_uri;}

Python模块和包

模块和包 为什么要有模块和包 在Python中&#xff0c;模块&#xff08;Module&#xff09;和包&#xff08;Package&#xff09;是组织和管理代码的重要工具&#xff0c;有助于将代码划分为可维护和重用的单元。 模块&#xff08;Module&#xff09; 概念&#xff1a;模块是…

Notes用户还可自助改密码

大家好&#xff0c;才是真的好。 很多时候企业对员工的安全使用进行了硬性规定&#xff0c;例如严格的就是&#xff0c;每三个月或六个月要至少更改一次密码。 在Domino 8.5以后&#xff0c;功能上多了一个新特性&#xff0c;叫ID保险库&#xff0c;其实就是把用户的id标识符…

day40 整数拆分 不同的二叉搜索树

题目1&#xff1a;343 整数拆分 题目链接&#xff1a;343 整数拆分 题意 将正整数n拆成k个正整数的和&#xff08;k>2&#xff09;使整数的乘积最大化 尽量拆成若干个数值近似相等的数&#xff0c;这使用的是数学里面的思想&#xff1a;ab<(a^2b^2)/2 (当且仅当ab时&…