Unity3d常用的数据结构的总结与分析

转自:慕容小匹夫   http://www.cnblogs.com/murongxiaopifu/p/4161648.html

1.几种常见的数据结构

 这里主要总结下小匹夫在工作中常碰到的几种数据结构:Array,ArrayList,List<T>,LinkedList<T>,Queue<T>,Stack<T>,Dictionary<K,T>

 数组Array:

  数组是最简单的数据结构。其具有如下特点:

  1. 数组存储在连续的内存上。
  2. 数组的内容都是相同类型。
  3. 数组可以直接通过下标访问。

  数组Array的创建:

1 int size = 5;
2 int[] test = new int[size];

  创建一个新的数组时将在 CLR 托管堆中分配一块连续的内存空间,来盛放数量为size,类型为所声明类型的数组元素。如果类型为值类型,则将会有size个未装箱的该类型的值被创建。如果类型为引用类型,则将会有size个相应类型的引用被创建。

  由于是在连续内存上存储的,所以它的索引速度非常快,访问一个元素的时间是恒定的也就是说与数组的元素数量无关,而且赋值与修改元素也很简单。

string[] test2 = new string[3];
//赋值
test2[0] = "chen";
test2[1] = "j";
test2[2] = "d";
//修改
test2[0] = "chenjd";

  但是有优点,那么就一定会伴随着缺点。由于是连续存储,所以在两个元素之间插入新的元素就变得不方便。而且就像上面的代码所显示的那样,声明一个新的数组时,必须指定其长度,这就会存在一个潜在的问题,那就是当我们声明的长度过长时,显然会浪费内存,当我们声明长度过短的时候,则面临这溢出的风险。这就使得写代码像是投机,小匹夫很厌恶这样的行为!针对这种缺点,下面隆重推出ArrayList。

 ArrayList:

  为了解决数组创建时必须指定长度以及只能存放相同类型的缺点而推出的数据结构。ArrayList是System.Collections命名空间下的一部分,所以若要使用则必须引入System.Collections。正如上文所说,ArrayList解决了数组的一些缺点。

  1. 不必在声明ArrayList时指定它的长度,这是由于ArrayList对象的长度是按照其中存储的数据来动态增长与缩减的。
  2. ArrayList可以存储不同类型的元素。这是由于ArrayList会把它的元素都当做Object来处理。因而,加入不同类型的元素是允许的。

  ArrayList的操作:

ArrayList test3 = new ArrayList();
//新增数据
test3.Add("chen");
test3.Add("j");
test3.Add("d");
test3.Add("is");
test3.Add(25);
//修改数据
test3[4] = 26;
//删除数据
test3.RemoveAt(4);

  说了那么一堆”优点“,也该说说缺点了吧。为什么要给”优点”打上引号呢?那是因为ArrayList可以存储不同类型数据的原因是由于把所有的类型都当做Object来做处理,也就是说ArrayList的元素其实都是Object类型的,辣么问题就来了。

  1. ArrayList不是类型安全的。因为把不同的类型都当做Object来做处理,很有可能会在使用ArrayList时发生类型不匹配的情况。
  2. 如上文所诉,数组存储值类型时并未发生装箱,但是ArrayList由于把所有类型都当做了Object,所以不可避免的当插入值类型时会发生装箱操作,在索引取值时会发生拆箱操作。这能忍吗?

注:为何说频繁的没有必要的装箱和拆箱不能忍呢?且听小匹夫慢慢道来:所谓装箱 (boxing):就是值类型实例到对象的转换(百度百科)。那么拆箱:就是将引用类型转换为值类型咯(还是来自百度百科)。下面举个栗子~

//装箱,将String类型的值FanyoyChenjd赋值给对象。
String  info = ”FanyoyChenjd”;
object obj=(object)info;  

//拆箱,从Obj中提取值给info
object obj = "FanyoyChenjd";
String info = (String)obj;

那么结论呢?好吧,请允许小匹夫很low再次引用百度百科。显然,从原理上可以看出,装箱时,生成的是全新的引用对象,这会有时间损耗,也就是造成效率降低。

 List<T>泛型List

  为了解决ArrayList不安全类型与装箱拆箱的缺点,所以出现了泛型的概念,作为一种新的数组类型引入。也是工作中经常用到的数组类型。和ArrayList很相似,长度都可以灵活的改变,最大的不同在于在声明List集合时,我们同时需要为其声明List集合内数据的对象类型,这点又和Array很相似,其实List<T>内部使用了Array来实现。

List<string> test4 = new List<string>();  

//新增数据
test4.Add(“Fanyoy”);
test4.Add(“Chenjd”);  

//修改数据
test4[1] = “murongxiaopifu”;  

//移除数据
test4.RemoveAt(0);  

  这么做最大的好处就是

  1. 即确保了类型安全。
  2. 也取消了装箱和拆箱的操作。
  3. 它融合了Array可以快速访问的优点以及ArrayList长度可以灵活变化的优点。

  LinkedList<T>

  也就是链表了。和上述的数组最大的不同之处就是在于链表在内存存储的排序上可能是不连续的。这是由于链表是通过上一个元素指向下一个元素来排列的,所以可能不能通过下标来访问。如图

  既然链表最大的特点就是存储在内存的空间不一定连续,那么链表相对于数组最大优势和劣势就显而易见了。

  1. 向链表中插入或删除节点无需调整结构的容量。因为本身不是连续存储而是靠各对象的指针所决定,所以添加元素和删除元素都要比数组要有优势。
  2. 链表适合在需要有序的排序的情境下增加新的元素,这里还拿数组做对比,例如要在数组中间某个位置增加新的元素,则可能需要移动移动很多元素,而对于链表而言可能只是若干元素的指向发生变化而已。
  3. 有优点就有缺点,由于其在内存空间中不一定是连续排列,所以访问时候无法利用下标,而是必须从头结点开始,逐次遍历下一个节点直到寻找到目标。所以当需要快速访问对象时,数组无疑更有优势。

  综上,链表适合元素数量不固定,需要经常增减节点的情况。

  关于链表的使用,MSDN上有详细的例子

  Queue<T>

  在Queue<T>这种数据结构中,最先插入在元素将是最先被删除;反之最后插入的元素将最后被删除,因此队列又称为“先进先出”(FIFO—first in first out)的线性表。通过使用Enqueue和Dequeue这两个方法来实现对 Queue<T> 的存取。

  一些需要注意的地方:

  1. 先进先出的情景。
  2. 默认情况下,Queue<T>的初始容量为32, 增长因子为2.0。
  3. 当使用Enqueue时,会判断队列的长度是否足够,若不足,则依据增长因子来增加容量,例如当为初始的2.0时,则队列容量增长2倍。
  4. 乏善可陈。

  关于Queue<T>的使用方法,MSDN上也有相应的例子

  Stack<T>

  

  与Queue<T>相对,当需要使用后进先出顺序(LIFO)的数据结构时,我们就需要用到Stack<T>了。

  一些需要注意的地方:

  1. 后进先出的情景。
  2. 默认容量为10。
  3. 使用pop和push来操作。
  4. 乏善可陈。

  同样,在这里你也可以看到大量Stack<T>的例子。

  Dictionary<K,T>

  字典这东西,小匹夫可是喜欢的不得了。看官们自己也可以想想字典是不是很招人喜欢,创建一个字典之后就可以往里面扔东西,增加、删除、访问那叫一个快字了得。但是直到小匹夫日前看了一个大神的文章,才又想起了那句话“啥好事咋能让你都占了呢”。那么字典背后到底隐藏着什么迷雾,拨开重重迷雾之后,是否才是真相?且听下回分。。。等等,应该是下面就让我们来分析一下字典吧。

  提到字典就不得不说Hashtable哈希表以及Hashing(哈希,也有叫散列的),因为字典的实现方式就是哈希表的实现方式,只不过字典是类型安全的,也就是说当创建字典时,必须声明key和item的类型,这是第一条字典与哈希表的区别。关于哈希表的内容推荐看下这篇博客哈希表。关于哈希,简单的说就是一种将任意长度的消息压缩到某一固定长度,比如某学校的学生学号范围从00000~99999,总共5位数字,若每个数字都对应一个索引的话,那么就是100000个索引,但是如果我们使用后3位作为索引,那么索引的范围就变成了000~999了,当然会冲突的情况,这种情况就是哈希冲突(Hash Collisions)了。扯远了,关于具体的实现原理还是去看小匹夫推荐的那篇博客吧,当然那篇博客上面那个大大的转字也是蛮刺眼的。。。

  回到Dictionary<K,T>,我们在对字典的操作中各种时间上的优势都享受到了,那么它的劣势到底在哪呢?对嘞,就是空间。以空间换时间,通过更多的内存开销来满足我们对速度的追求。在创建字典时,我们可以传入一个容量值,但实际使用的容量并非该值。而是使用“不小于该值的最小质数来作为它使用的实际容量,最小是3。”(老赵),当有了实际容量之后,并非直接实现索引,而是通过创建额外的2个数组来实现间接的索引,即int[] buckets和Entry[] entries两个数组(即buckets中保存的其实是entries数组的下标),这里就是第二条字典与哈希表的区别,还记得哈希冲突吗?对,第二个区别就是处理哈希冲突的策略是不同的!字典会采用额外的数据结构来处理哈希冲突,这就是刚才提到的数组之一buckets桶了,buckets的长度就是字典的真实长度,因为buckets就是字典每个位置的映射,然后buckets中的每个元素都是一个链表,用来存储相同哈希的元素,然后再分配存储空间。

因此,我们面临的情况就是,即便我们新建了一个空的字典,那么伴随而来的是2个长度为3的数组。所以当处理的数据不多时,还是慎重使用字典为好,很多情况下使用数组也是可以接受的。

2.几种常见数据结构的使用情景

Array

需要处理的元素数量确定并且需要使用下标时可以考虑,不过建议使用List<T>

ArrayList

不推荐使用,建议用List<T>

List<T>泛型List

需要处理的元素数量不确定时 通常建议使用

LinkedList<T>

链表适合元素数量不固定,需要经常增减节点的情况,2端都可以增减

Queue<T>

先进先出的情况

Stack<T>

后进先出的情况

Dictionary<K,T>

需要键值对,快速操作
时间: 2024-10-13 22:24:42

Unity3d常用的数据结构的总结与分析的相关文章

Unity3D中常用的数据结构总结与分析

Unity3D中常用的数据结构总结与分析 c#语言规范 阅读目录 1.几种常见的数据结构 2.几种常见数据结构的使用情景 来到周末,小匹夫终于有精力和时间来更新下博客了.前段时间小匹夫读过一份代码,对其中各种数据结构灵活的使用赞不绝口,同时也大大激发了小匹夫对各种数据结构进行梳理和总结的欲望.正好最近也拜读了若干大神的文章,觉得总结下常用的数据结构以供自己也能灵活的使用变得刻不容缓.那么还是从小匹夫的工作内容入手,就谈谈在平时使用U3D时经常用到的数据结构和各种数据结构的应用场景吧. 回到目录

python数据结构与算法 38 分析树

分析树 树的结构完成以后,该是时候看看它能做点什么实事儿了.这一节里,我们研究一下分析树.分析树能够用于真实世界的结构表示,象语法或数学表达式一类的. 图1 一个简单语句的分析树 图1所示是一个简单语句的层级结构,把语句表示为树结构可以让我们用子树来分析句子的组成部分. 图2 ((7+3)?(5?2))的分析树 我们也可以把数学表达式如((7+3)?(5?2))表示为分析树,如图2.此前我们研究过完全括号表达式,这个表达式表达了什么呢?我们知道乘法的优先级比加减要高,但因为括号的关系,在做乘法之

游戏制作中的大宝剑---常用的数据结构与算法

前言 时间流逝,物是人非,就好像涌动的河流,永无终焉,幼稚的心智将变得高尚,青年的爱慕将变得深刻,清澈之水折射着成长. ----------<塞尔塔传说> PS:为了方便大家阅读,个人认为比较重要的内容-------红色字体显示 个人认为可以了解的内容-------紫色字体显示 --------------------------------------------------------------------------- ---------------------------------

关于海量数据常用的数据结构

数据结构 应用场景 示例 哈希表 要求所有键值对放入内存,查找可以在常数时间内完成. l  提取某日志访问百度次数最多的IP l  统计不同电话号码的个数 堆 插入和调整需要O(logn)时间,n为堆元素的个数,而获取堆顶元素只需要常数时间. l  求出海量数据前K大的数 l  求海量数据流的中位数 BitMap 通常记录整数出现的情况,用来快速查找.数字判重.删除元素等. l  统计不同电话号码的个数 l  2.5亿个整数中查出不同重复的整数个数 双层桶 两次寻址方式以节省内存,通常用在求第K

Python 常用查找数据结构及算法

一.基本概念 二.无序表查找 三.有序表查找 3.1 二分查找(Binary Search) 3.2 插值查找 3.3 斐波那契查找 四.线性索引查找 4.1 稠密索引 4.2 分块索引 4.3 倒排索引 五.二叉排序树 六. 平衡二叉树 七.多路查找树(B树) 7.1 2-3树 7.2 2-3-4树 7.3 B树 7.4 B+树 八.散列表(哈希表) 8.1 散列函数的构造方法 8.2 处理散列冲突 8.3 散列表查找实现 8.4 散列表查找性能分析 参考书目<大话数据结构> 一.基本概念

java中常用的数据结构--Collection接口及其子类

java中有几种常用的数据结构,主要分为Collection和map两个主要接口(接口只提供方法,并不提供实现),而程序中最终使用的数据结构是继承自这些接口的数据结构类. 一.集合和数组的区别 二.Collection集合和Map集合 三.Collection接口 1.定义 public interface Collection<E> extends Iterable<E> {} 它是一个接口,是高度抽象出来的集合,它包含了集合的基本操作:添加.删除.清空.遍历(读取).是否为空.

在使用R做数据挖掘时,最常用的数据结构莫过于dataframe了,下面列出几种常见的dataframe的操作方法

原网址 http://blog.sina.com.cn/s/blog_6bb07f83010152z0.html 在使用R做数据挖掘时,最常用的数据结构莫过于dataframe了,下面列出几种常见的dataframe的操作方法.1.查看数据 head(dataframe) # 查看数据前10行tail(dataframe) # 查看数据后10行 2.合并数据(1)data.frame(x,y)x,y是dataframe或者一列数据,x和y的行数一样,该操作得到一个新的dataframe,该dat

一些常用的数据结构维护手法

这篇会理论上讲一讲常用的数据结构维护手法. 我是嘴巴选手我自豪! ①cdq分治 现在我们有一些修改,有一些询问,修改之间独立. 我们考虑分治,对于左右两半分别分治,然后对于左边的修改计算对右边询问的贡献. 本身的复杂度是O(nlogn). ②整体二分 现在我们有一些修改,有一些询问. 我们需要求出,在最少多少组修改之后满足题目条件.(或者可以转化成这样) 对于单组询问,我会二分!对于多组询问,真不巧,二分超时了... 我们考虑整体二分.整体二分的框架大概是这样: def 整体二分(el,er,q

Unity3D 常用 英文单词

Unity3D 常用 英文单词 Tutorial:辅导,辅助 pivot:中心点:枢轴 diffuse:扩散:四散 assets:资源 Camera:相机 icon:图标:肖像 cube:立方体 Rotation:旋转.循环 Scale:刻度,比例 Collider:对碰机,碰撞机 Transform:改变,变换 Pillar:柱子 prefab:预设,预制 FPS Controller:第一人称控制器 rigid:坚硬的  rigidbody 刚体 trigger:触发器 preference