常用数据结构

常用数据结构复杂度

数据结构AddDeleteFindGetByIndex
ArrayO(n)O(n)O(n)O(1)
ArrayListO(1)O(n)O(n)O(1)
List<T>O(1)O(n)O(n)O(1)
LinkedList<T>O(1)O(n)O(n)O(n)
StackO(1)O(1)--
QueueO(1)O(1)--
HashTableO(1)O(1)O(1)-
DictionaryO(1)O(1)O(1)-
HashSet<T>O(1)O(1)O(1)-
SortedSet<T>O(log n)O(log n)O(log n)-

Array数组

Array数组具有3个特点。
1. 数组存储在连续的内存上。
2. 数组元素都是相同类型。
3. 数组可以通过下标访问。
Unity在创建新数组时,将在Mono运行时的托管堆中分配一块连续的内存空间来盛放数组元素。由于在连续内存上存储,所以数组的索引速度非常快,访问时间和元素数量无关。但在两个元素中间插入新元素就很不方便。同时,在数组的声明中,如果声明数组长度过长,会浪费内存,过短则会有溢出的风险。

ArrayList数组

ArrayList是System.Collections命名空间下的一部分。它解决了一些Array的一些缺点。
1. 不必在声明ArrayList时指明它的长度。其长度是根据存储的数据动态增长的。
2. ArrayList可以存储不同类型的元素。ArrayList会把它存储的元素作为Object来处理,所以一个ArrayList数组可以加入不同类型的元素。

这里又出现了新的问题:
- ArrayList是类型不安全的。它将所有的元素都作为Object来处理,这样在提取元素的时候可能会发生类型不匹配的情况。
- 可能存在的频繁的拆装箱。数组在存储值类型时并未发生装箱。但是ArrayList将所有的元素都作为Object类型来处理,所以在插入值类型时会发生装箱操作,在索引取值的时候又会发生拆箱操作。此时频繁的读写ArrayList会产生额外开销。

List<T>

在C#引入了泛型的概念后,List<T>作为一种新的数组类型引入。它解决了ArrayList不安全类型和装箱拆箱的缺点,可以将其认为是ArrayList的泛型等效类,在声明集合时,同时要求声明集合内数据的类型。其实List<T>内部使用了Array来实现,但它隐藏了这些实现的复杂性。List<T>有以下几个好处:
- 确保了类型安全。
- 减少了装箱拆箱的操作。
- 融合了Array快速访问和ArrayList长度灵活的特点。

LinkedList<T>

链表,仅需持有第一个结点-HEAD,就可以通过逐个访问下个节点“NEXT”来遍历链表中的所有节点。链表最主要的优势是在向链表中插入或者删除节点的时候,不需要考虑容量的改变,只需要改变上一个节点的NEXT即可。而数组的内容在内存中连续,如果要存放更多的数据,就需要考虑调成数组容量,从而引发新建数组、数据拷贝等问题。
C#为我们提供了LinkedList<T>和LinkedListNode供我们使用,但在实际开发中,更多的是根据自己的需求利用其思想来创建合适链表。

Queue<T>和Stack<T>

队列(Queue<T>)和栈(Stack<T>)都属于是受限制的线性表。
队列仅允许在其表的前端进行删除操作(队头),在表的后端进行插入操作(队尾)。当我们使用先进先出(FIFO)的数据结构时,可以使用队列。
栈仅允许在表的一段进行插入和删除操作,这一段称为栈顶,相对的将另一端称为栈底。在需要使用后进先出(LIFO)的数据结构时,可以使用栈。
在C#中,Queue<T>内部是存放类型为T的环形数组。Queue<T>接受Null作为引用类型的有效值。其初始化容量为32,当然也可以指定容量。在使用Enquque进行插入时,会判断长度是否足够,如果不够则容量增长为2倍。而Stack<T>内部可以看作是垂直的数组,每次操作至对栈顶的元素进行操作。

Hash Table和Dictionary<K,T>

哈希表(Hash Table)和字典(Dictionary<K,T>)是根据关键码/值(Key/Value)来直接进行访问的数据结构,从而加快了查找的速度。多用于需要使用键值对来快速查找,且元素没有特定顺序的时候。
Hash Table不是泛型,其元素属于Object类型,说明其类型不安全。而Dictionary<K,T>在使用时必须指定Key和Value的类型。
另外需要注意,Dictionary<K,T>存在以空间换时间的缺点,每次创建时,传入的容量值并不是实际容量值,而是大于该值的最小质数,容量的最小值为3。


装箱和拆箱

简单来说,装箱就是将值类型转化为引用类型,拆箱就是将引用类型转化为值类型。如下所示:

int a=1;
string str=a;
//装箱。1.在托管堆中分配内存。2.将值类型的字段复制到新分配的内存堆中。3.返回对象地址,即对象的引用。
int b=int.Parse(str);
//拆箱。

这里需要注意,拆箱不涉及到复制的过程,所以将值从托管堆上的对象复制到值类型实例中,是拆箱之后紧跟的复制过程,而非拆箱本身。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值