C#深度理解:数组、集合、哈希、字典、堆、栈 优缺点
一、数组
1、Array 固定数组
优点:
1). 快速访问:数组通过索引来访问元素,访问速度非常快,因为可以通过索引进行直接定位。
2). 内存连续存储:数组在内存中以连续的方式存储元素,这样有助于提高数据的读取和写入效率。
3). 多维支持:C#中的数组支持多维(二维、三维等)数据结构,可以用于表示矩阵、表格等复杂数据。
4). 值类型和引用类型:数组可以存储值类型和引用类型的数据,这种灵活性使得数组在各种场景中都有应用。
缺点:
1). 固定长度:一旦创建了数组,其长度就是固定的,无法动态地增加或减少。如果需要动态调整长度,需要创建新的数组并复制数据。
2). 缺乏灵活性:数组的长度一旦确定,就无法改变。这种固定长度的限制对于某些场景可能不够灵活,需要使用其他数据结构。
3). 空间浪费:如果数组长度较大,但实际存储的元素数量较少,会导致空间的浪费。因为数组分配的内存是根据指定长度来进行的,无法动态调整。
4). 插入和删除效率低:由于数组是连续存储的,插入和删除元素时需要将后面的元素向前或向后移动,效率较低。
2、ArrayList 动态数组
优点:
1). 动态大小:ArrayList在创建时不需要指定大小,可以根据需要动态添加和删除元素。
2). 可以存储不同类型的对象:ArrayList可以存储不同类型的对象,例如整数、字符串、对象等。
3). 可以快速访问元素:可以使用索引来快速访问ArrayList中的元素。
缺点:
1). 强制类型转换:由于ArrayList可以存储不同类型的对象,因此在访问时需要进行强制类型转换。
2). 性能开销:由于ArrayList是一个动态数组,添加和删除元素可能涉及到内存重新分配,导致性能开销。
二、集合
1、List 泛型集合
优点:
1). 类型安全:List是一个泛型类,可以指定存储的对象类型,避免了类型转换的开销,提高了代码的安全性和可读性。
2). 动态大小:List在创建时不需要指定大小,可以根据需要动态添加和删除元素。
3). 高效的索引查找:与ArrayList不同,List有更高效的索引查找,因为它是基于数组实现的。
4). 提供多种操作方法:List提供了丰富的操作方法,如排序、查找、过滤等,方便进行集合操作。
缺点:
1). 只能存储同一类型的对象:由于List是泛型类,只能存储同一类型的对象,无法存储不同类型的对象。
2、IEnumerable 泛型集合
优点:
1). 泛型支持:IEnumerable是一个泛型接口,可以指定集合中的元素类型,提高了代码的类型安全性和可读性。
2). 延迟执行:IEnumerable使用迭代器的方式进行遍历,只在需要时才会产生结果,可以减少内存消耗,提高性能。
3). 抽象通用:IEnumerable是一个通用的遍历接口,可以用来遍历各种集合类型,提供了统一的遍历语义。
缺点:
1). 单向遍历:IEnumerable只支持单向的前进遍历,无法直接进行逆序遍历或随机访问。
三、哈希\字典
1、HashTable 非泛型集合类
Hashtable是C#中的一个非泛型集合类,它提供了键值对的存储方式。
优点:
1). 高效的查找性能:Hashtable使用哈希算法进行查找,具有快速的查找速度,适用于大量数据的快速访问。
2). 动态扩展:Hashtable可以根据需要自动扩展其容量,当存储的数据量增加时,它会自动重新分配内部存储空间,无需手动管理。
缺点:
1). 不支持泛型:Hashtable是一个非泛型集合类,存储的键和值都是Object类型,可能需要进行类型转换。
2). 无序性:Hashtable中的键值对是没有固定的顺序的,无法按照特定的顺序进行遍历或访问。
2、Dictionary 键值对集合类--字典
C#中的Dictionary是一种键值对集合,它使用哈希表实现,在插入、删除和查找操作上具有高效的性能。
优点:
1). 快速的查找:Dictionary内部使用哈希表来存储数据,可以通过键来快速查找对应的值,平均查找时间复杂度为O(1)。
2). 唯一键:Dictionary要求键的唯一性,保证了键的唯一性,防止重复的键的存在。
3). 内存效率:相对于其他集合类型,Dictionary在存储大量数据时,具有较低的内存占用。
缺点:
1). 内存消耗:由于Dictionary使用哈希表来存储数据,需要使用额外的内存空间来存储哈希表和键值对对象。
2). 无序集合:Dictionary中的元素是无序的,并不像SortedSet或List那样保持有序。
3、HashSet 无序、唯一、自动去重集合类
HashSet是C#中的一个集合类,它提供了一种无序、唯一的集合方式,不允许重复的元素。
优点:
1). 快速的查找性能:HashSet内部使用哈希表实现,具有快速的查找速度,适用于需要频繁查找元素的场景。
2). 不允许重复元素:HashSet保证集合中的元素是唯一的,当尝试添加重复的元素时,只会得到一个元素,不会重复添加。
缺点:
1). 无序性:HashSet中的元素是没有固定的顺序的,无法按照特定的顺序进行遍历或访问。
2). 不支持索引访问:HashSet中的元素没有索引,无法通过索引直接访问元素,只能通过迭代器进行遍历。
4、SortedSet 有序、自动排序集合类
C#中的SortedSet是一个有序集合,它基于红黑树实现,提供了高效的插入、删除和查找操作。
优点:
1). 自动排序:SortedSet会按照元素的自然顺序(或者通过自定义的比较器)自动对元素进行排序,使元素始终保持有序状态。
2). 快速的插入和删除:SortedSet利用红黑树的特性,插入和删除操作的时间复杂度为O(log n),效率较高。
3). 唯一性:SortedSet不允许重复的元素存在,保证了集合中的元素唯一性。
缺点:
1). 需要额外的内存:SortedSet使用了红黑树来维护有序状态,这需要额外的内存空间来存储树的结构信息。
2). 不支持随机访问:SortedSet不支持通过索引或者下标直接访问集合的元素,只能通过迭代器按照顺序遍历元素。
四、堆\栈
1、Heap 堆-->先进先出原则
优点:
1). 可以动态分配内存:堆允许在运行时动态分配内存,可以根据需要创建和销毁对象。这样可以避免静态分配内存时的空间浪费。
2). 对象生命周期灵活:堆上的对象的生命周期不受作用域的限制,可以在整个应用程序中使用。这提供了更大的灵活性,可以在不同的方法和类之间共享对象。
3). 处理大型数据结构:堆空间较大,适合存储大型数据结构和复杂的对象。这对于处理大量数据的应用程序非常有用,比如图形处理、数据库操作等。
缺点:
1). 内存管理开销:堆上的内存由垃圾回收器(Garbage Collector)来管理,这会带来一定的开销。垃圾回收器会不断扫描堆上的对象,释放不再使用的对象,但这个过程可能会导致一些性能损失。
2). 内存碎片:由于堆的动态分配,堆空间可能会出现内存碎片的问题。频繁的创建和销毁对象会导致堆空间中出现不连续、零散的内存块。这可能会影响内存的分配效率和性能。
3). 对象访问速度较慢:由于堆上的对象是动态分配的,需要通过引用来访问。相比之下,栈上的数据是直接存储的,访问更快。因此,在性能要求较高的场景下,堆上的对象可能会导致一定的性能损失。
2、Stack 栈-->先进后出原则
优点:
1). 内存管理速度快:栈上的数据是按照LIFO(后进先出)的原则进行分配和销毁,这种分配方式非常高效,只需移动栈指针即可完成。
2). 内存访问速度快:由于栈上的数据是直接存储的,因此对于栈上的变量和对象的访问速度非常快。
缺点:
1). 内存空间有限:栈的大小在编译时就确定了,通常较小。因此,栈上只适合存储较小的简单数据类型和引用,不能用于存储大型数据结构和复杂的对象。
2). 对象生命周期受限:栈上的对象的生命周期受限于其所在的作用域,一旦作用域结束,对象就被销毁。这限制了对象的跨作用域使用和共享。
以上就是数组、集合、哈希、字典、堆、栈 优缺点的简单介绍