No title
No title
John Doe集合类
Array(数组)和ArrayList(集合)关键区别
- 类型安全:
Array
:类型安全,数组中的所有元素必须是相同的类型。ArrayList
:非类型安全,可以包含任何类型的对象。
- 大小:
Array
:大小固定,必须在创建时指定。ArrayList
:大小动态调整,根据需要自动扩展。
- 性能:
Array
:性能较好,直接操作内存。ArrayList
:性能较差,因为它需要处理动态扩展和类型转换。
- 用途:
Array
:适用于需要固定大小和类型安全的场景。ArrayList
:适用于需要动态大小且类型不确定的场景,但推荐使用List<T>
代替ArrayList
。
ArrayList
1. 特性
- 动态大小:
ArrayList
能够自动调整大小。它会在添加元素时动态扩展容量。 - 非类型安全:
ArrayList
可以存储任何类型的对象。这可能会导致类型不安全的问题,因为你需要在取出元素时进行类型转换。 - 对象存储:
ArrayList
存储的是object
类型的对象,因此你可以存储不同类型的对象,但需要在使用时进行强制类型转换。 - 它属于
System.Collections
命名空间
2. 常用方法
- 添加元素:
Add(object value)
:将元素添加到集合的末尾。AddRange(ICollection c)
:将指定的集合中的元素添加到ArrayList
的末尾。Insert(int index, object value)
:在指定索引处插入元素。InsertRange(int index, ICollection c)
:在指定索引处插入指定集合中的元素。
- 移除元素:
Remove(object obj)
:移除第一个匹配的元素。RemoveAt(int index)
:移除指定索引处的元素。RemoveRange(int index, int count)
:移除从指定索引开始的指定数量的元素。Clear()
:清空整个集合。
- 查找和排序:
Contains(object obj)
:确定集合是否包含指定的元素。IndexOf(object obj)
:返回指定元素在集合中的索引。Sort()
:对集合进行排序。Reverse()
:反转集合中的元素。
- 访问和枚举:
this[int index]
:通过索引访问集合中的元素。Enumerator
:返回一个用于遍历集合的枚举器。
3. 性能
- 容量管理:
ArrayList
会在容量不足时进行扩容。默认情况下,扩容策略是将容量增加到原来的两倍。 - 性能问题:由于需要处理对象类型,
ArrayList
在性能上可能会逊色于泛型集合(如List<T>
)。此外,频繁的扩容和类型转换也可能影响性能。
4. 现代替代方案
- **
List<T>
**:是 .NET 中推荐的泛型集合类,属于System.Collections.Generic
命名空间。List<T>
提供类型安全和更好的性能。- 例如,
List<int>
只能存储int
类型的元素,避免了类型转换问题。 List<T>
提供了与ArrayList
相似的方法,如添加、移除、排序等,但在类型安全和性能上优于ArrayList
。
- 例如,
1 | ArrayList arrayList = new ArrayList(); |
List
1. 特性
- 泛型:
List<T>
是一个泛型类,T
表示集合中元素的类型。这使得List<T>
类型安全,不需要进行类型转换。 - 动态大小:
List<T>
能够自动调整大小,随着元素的添加或移除而动态扩展或收缩。 - 高效:相比于非泛型集合(如
ArrayList
),List<T>
提供了更好的性能和类型安全。 List<T>
是 .NET 中提供的一个泛型集合类,属于System.Collections.Generic
命名空间。List<T>
用于存储同一类型的对象集合
2. 常用方法
- 添加元素:
Add(T item)
:将元素添加到集合的末尾。AddRange(IEnumerable<T> collection)
:将指定集合中的元素添加到List<T>
的末尾。
- 插入元素:
Insert(int index, T item)
:在指定索引处插入元素。InsertRange(int index, IEnumerable<T> collection)
:在指定索引处插入指定集合中的元素。
- 移除元素:
Remove(T item)
:移除第一个匹配的元素。RemoveAt(int index)
:移除指定索引处的元素。RemoveRange(int index, int count)
:移除从指定索引开始的指定数量的元素。Clear()
:清空整个集合。
- 查找和排序:
Contains(T item)
:确定集合是否包含指定的元素。IndexOf(T item)
:返回指定元素在集合中的索引。Sort()
:对集合进行排序。Reverse()
:反转集合中的元素。Find(Predicate<T> match)
:查找第一个符合条件的元素。FindAll(Predicate<T> match)
:查找所有符合条件的元素。FindIndex(Predicate<T> match)
:查找第一个符合条件的元素的索引。FindLast(Predicate<T> match)
:查找最后一个符合条件的元素。FindLastIndex(Predicate<T> match)
:查找最后一个符合条件的元素的索引。
- 访问和枚举:
this[int index]
:通过索引访问集合中的元素。Enumerator
:返回一个用于遍历集合的枚举器。
3. 性能
- 容量管理:
List<T>
会在容量不足时自动扩展,通常扩展策略是将容量增加到原来的两倍。你可以通过设置Capacity
属性来预设容量,避免频繁扩容。 - 性能优势:
List<T>
提供的类型安全和泛型支持使得在访问和操作集合时性能优于非泛型集合(如ArrayList
)。内存使用和访问速度更高,避免了类型转换和装箱/拆箱操作。
4. 比较与替代方案
- **
ArrayList
**:ArrayList
是非泛型集合,存储object
类型的元素。List<T>
替代ArrayList
提供了类型安全和更好的性能。 - **
LinkedList<T>
**:LinkedList<T>
是另一种泛型集合,适用于需要频繁插入和删除元素的场景,而List<T>
更适合需要随机访问和顺序操作的场景。 - **
Queue<T>
和Stack<T>
**:这些集合适用于特定的数据结构需求,如先进先出(FIFO)或后进先出(LIFO)的数据处理。
1 | // 创建 List<int> 并初始化 |
Dictionary<TKey, TValue>
1. 特性
- 键值对存储:
Dictionary<TKey, TValue>
存储一组键值对,其中TKey
是键的类型,TValue
是值的类型。 - 键唯一:每个键在字典中必须唯一。如果尝试添加一个已经存在的键,会抛出异常。
- 无序集合:
Dictionary<TKey, TValue>
不保证键值对的顺序。它内部使用哈希表来存储数据,提供快速的查找性能。 - 泛型:支持泛型,提供类型安全的集合操作。
Dictionary<TKey, TValue>
是 .NET 中的一个泛型集合类,属于System.Collections.Generic
命名空间。
2. 常用方法
添加和移除:
Add(TKey key, TValue value)
:添加一个键值对到字典中。如果键已存在,会抛出异常。Remove(TKey key)
:移除指定键及其对应的值。Clear()
:移除字典中的所有键值对。
访问元素:
this[TKey key]
:通过键访问字典中的值。如果键不存在,会抛出异常。TryGetValue(TKey key, out TValue value)
:尝试获取指定键的值,返回一个布尔值表示是否成功。
查询操作:
ContainsKey(TKey key)
:检查字典是否包含指定的键。ContainsValue(TValue value)
:检查字典是否包含指定的值。Count
:获取字典中的键值对数量。
枚举和迭代:
Keys
:获取一个包含字典所有键的集合。// 获取所有键 ICollection<string> keys = dictionary.Keys;
Values
:获取一个包含字典所有值的集合。// 获取所有值 ICollection<int> values = dictionary.Values;
Enumerator
:返回一个用于遍历字典的枚举器。(不常用)1
2
3
4
5
6
7
8
9
10
11
12// 获取枚举器
var enumerator = dictionary.GetEnumerator();
Console.WriteLine("Dictionary contents:");
while (enumerator.MoveNext())
{
KeyValuePair<string, int> kvp = enumerator.Current;
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
// 释放枚举器(虽然在 using 块内不一定需要显示调用 Dispose,但这样做有助于保持良好的习惯)
enumerator.Dispose();
3. 性能
- 查找性能:
Dictionary<TKey, TValue>
的查找操作具有 O(1) 平均时间复杂度,适合需要高效查找的场景。 - 扩容:
Dictionary<TKey, TValue>
会在容量不足时自动扩展,通常使用哈希表的方式来提高性能。 - 内存使用:由于使用哈希表实现,字典的内存使用可能会比其他集合类略高,但提供了更高效的查找操作。
4. 比较与替代方案
- **
Hashtable
**:Hashtable
是一个非泛型集合,用于存储键值对。相比于Dictionary<TKey, TValue>
,Hashtable
不提供类型安全,且在性能和灵活性方面较差。Dictionary<TKey, TValue>
是Hashtable
的泛型替代方案。 - **
SortedDictionary<TKey, TValue>
**:SortedDictionary<TKey, TValue>
是按键排序的字典,提供了键的排序视图,适用于需要按顺序遍历的场景。 - **
ConcurrentDictionary<TKey, TValue>
**:ConcurrentDictionary<TKey, TValue>
是线程安全的字典,适用于多线程环境中的并发操作。
1 | // 创建 Dictionary 并初始化 |
字典排序
1. 按键排序
var sortedByKey = dictionary.OrderBy(kvp => kvp.Key);
2. 按值排序
var sortedByValue = dictionary.OrderBy(kvp => kvp.Value);
3. 按值降序排序
var sortedByValueDescending = dictionary.OrderByDescending(kvp => kvp.Value);
4. 将排序后的结果转换回字典
var sortedDictionary = dictionary.OrderBy(kvp => kvp.Value).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
队列(Queue<T>
)
1. 特性
先进先出:队列中的元素按照它们添加的顺序进行处理。最早添加的元素最早被取出。
泛型:
Queue<T>
是泛型集合,T
表示队列中元素的类型。这提供了类型安全和避免了类型转换的需要。动态大小:队列可以动态调整大小,根据需要自动扩展。
元素值可重复。
Queue<T>
是 .NET 中的一个泛型集合类,属于System.Collections.Generic
命名空间。
2. 常用方法
- 添加元素:
Enqueue(T item)
:将元素添加到队列的末尾。
- 移除元素:
Dequeue()
:移除并返回队列的开头元素。如果队列为空,调用此方法会抛出异常。TryDequeue(out T result)
:尝试从队列中移除并返回开头元素。如果队列为空,返回false
。
- 访问元素:
Peek()
:返回队列的开头元素,但不移除它。如果队列为空,调用此方法会抛出异常。TryPeek(out T result)
:尝试返回队列的开头元素,但不移除它。如果队列为空,返回false
。
- 查询操作:
Contains(T item)
:检查队列是否包含指定的元素。Count
:获取队列中的元素数量。
- 清空队列:
Clear()
:清空队列中的所有元素。
- 枚举和迭代:
Enumerator
:返回一个用于遍历队列中元素的枚举器。
3. 性能
- 时间复杂度:
Enqueue
和Dequeue
操作的时间复杂度为 O(1),这是由于队列内部通常使用循环缓冲区实现。Peek
操作的时间复杂度也为 O(1)。Contains
操作的时间复杂度为 O(n),因为需要遍历队列来查找元素。
- 空间复杂度:空间复杂度取决于队列的大小。
Queue<T>
动态调整大小,以适应元素的添加和移除。
4. 比较与替代方案
- **
LinkedList<T>
**:LinkedList<T>
提供了类似的先进先出的操作,但支持更灵活的插入和删除操作。适用于需要频繁插入和删除的场景。 - **
ConcurrentQueue<T>
**:如果在多线程环境中使用队列,ConcurrentQueue<T>
是线程安全的队列实现,适用于并发场景。 - **
Stack<T>
**:与队列不同,Stack<T>
实现的是后进先出(LIFO, Last-In-First-Out)数据结构,适用于不同的数据处理需求。
1 | // 创建 Queue 并初始化 |
栈(Stack<T>
)
1. 特性
- 后进先出:栈中的元素按照它们添加的相反顺序进行处理。最后添加的元素最早被取出。
- 泛型:
Stack<T>
是泛型集合,T
表示栈中元素的类型。这提供了类型安全,避免了类型转换的需要。 - 动态大小:栈可以动态调整大小,根据需要自动扩展。
Stack<T>
是 .NET 中提供的泛型集合类,属于System.Collections.Generic
命名空间。
2. 常用方法
- 添加元素:
Push(T item)
:将元素推入栈顶。
- 移除元素:
Pop()
:移除并返回栈顶的元素。如果栈为空,调用此方法会抛出异常。TryPop(out T result)
:尝试从栈中移除并返回栈顶元素。如果栈为空,返回false
。
- 访问元素:
Peek()
:返回栈顶的元素,但不移除它。如果栈为空,调用此方法会抛出异常。TryPeek(out T result)
:尝试返回栈顶的元素,但不移除它。如果栈为空,返回false
。
- 查询操作:
Contains(T item)
:检查栈中是否包含指定的元素。Count
:获取栈中的元素数量。
- 清空栈:
Clear()
:清空栈中的所有元素。
- 枚举和迭代:
Enumerator
:返回一个用于遍历栈中元素的枚举器。
3. 性能
- 时间复杂度:
Push
和Pop
操作的时间复杂度为 O(1),因为栈通常使用数组或链表来实现。Peek
操作的时间复杂度也为 O(1)。Contains
操作的时间复杂度为 O(n),因为需要遍历栈来查找元素。
- 空间复杂度:空间复杂度取决于栈的大小。
Stack<T>
动态调整大小,以适应元素的添加和移除。
4. 比较与替代方案
- **
LinkedList<T>
**:LinkedList<T>
也支持栈的操作,可以用AddLast
和RemoveLast
实现类似的后进先出功能。LinkedList<T>
更适合需要频繁插入和删除操作的场景。 - **
ConcurrentStack<T>
**:如果在多线程环境中使用栈,ConcurrentStack<T>
是线程安全的栈实现,适用于并发场景。 - **
Queue<T>
**:与栈不同,Queue<T>
实现的是先进先出(FIFO, First-In-First-Out)数据结构,适用于不同的数据处理需求。
1 | // 创建 Stack 并初始化 |
双向链表(LinkedList)
1. 特性
- 双向链表:
LinkedList<T>
是双向链表实现,每个节点都有对前驱节点和后继节点的引用。 - 动态大小:链表的大小可以动态调整,根据需要自动扩展或收缩。
- 不支持随机访问:与数组或列表不同,链表不支持通过索引进行随机访问。访问元素需要从头节点或尾节点开始遍历链表。
2. 常用方法
- 添加节点:
AddFirst(T value)
:在链表的开头插入一个新节点。AddLast(T value)
:在链表的末尾插入一个新节点。AddBefore(LinkedListNode<T> node, T value)
:在指定节点之前插入一个新节点。AddAfter(LinkedListNode<T> node, T value)
:在指定节点之后插入一个新节点。
- 移除节点:
Remove(T value)
:移除链表中第一个具有指定值的节点。RemoveFirst()
:移除链表中的第一个节点。RemoveLast()
:移除链表中的最后一个节点。Remove(LinkedListNode<T> node)
:移除指定的节点。
- 访问节点:
First
:获取链表的第一个节点。Last
:获取链表的最后一个节点。
- 清空链表:
Clear()
:移除链表中的所有节点。
- 查询操作:
Contains(T value)
:检查链表中是否包含具有指定值的节点。
- 枚举和迭代:
Enumerator
:返回一个用于遍历链表中节点的枚举器。
3. 性能
- 时间复杂度:
AddFirst
和AddLast
操作的时间复杂度为 O(1),因为这些操作只涉及更新节点的引用。RemoveFirst
和RemoveLast
操作的时间复杂度为 O(1),因为这些操作也只涉及更新节点的引用。Remove
和Contains
操作的时间复杂度为 O(n),因为需要遍历链表来查找元素。- 访问特定位置的元素(如通过节点引用)需要 O(n) 时间,因为链表不支持随机访问。
- 空间复杂度:每个节点需要额外的空间来存储对前驱节点和后继节点的引用,这会增加链表的内存开销。
4. 比较与替代方案
- **
List<T>
**:List<T>
是基于数组的动态集合,支持高效的随机访问。适用于需要频繁访问和修改元素的场景。与LinkedList<T>
相比,List<T>
的插入和删除操作可能较慢(O(n)),但支持更快的索引访问。 Queue<T>
和 **Stack<T>
**:这些集合类提供了特定的操作(先进先出和后进先出),适用于需要这些操作的场景。Queue<T>
和Stack<T>
的实现与LinkedList<T>
不同,但可以用来实现类似的功能。ConcurrentQueue<T>
和 **ConcurrentStack<T>
**:在多线程环境中使用队列或栈时,这些线程安全的实现可以避免同步问题。
1 | // 创建 LinkedList 并初始化 |
其它
1。数组和集合概念,以及它们的区别:
数组【一般是相同数据类型】(object[]数组元素类型可以不同)的元素按一定顺序排列的集合。
数组在添加,插入,删除不方便。说明数组不是链表。
数组是集合,集合不一定是数组。Collection
数组读取(查询)速度比集合快。集合是线性表,在插入,添加,删除数据时比较方便,性能比数组会高。
数组存储的类型不限制。集合存储的类型只能是引用类型。
C#中的集合(Collection)和数组(Array)是两种不同的数据结构,它们之间有以下主要区别:
1。定义方式不同:集合是使用集合类定义的,如List或HashSet。数组是使用类型和大小显式定义的。
2。大小不同:数组的大小在创建后无法更改,而集合的大小可以根据需要动态增长。
3。内存布局不同:数组在内存中是连续的,而集合通常不是。
4。性能不同:访问数组元素通常比访问集合元素快,因为集合元素访问时可能需要进行装箱和拆箱操作。
5。索引访问:数组可以通过索引直接访问元素,而集合则需要使用迭代器或者在.NET 2.0及以上版本中使用foreach循环。
6。数据类型不同:数组可以存储基本数据类型(值类型),也可以存储引用类型,【而集合只能存储引用类型】,因为它们都继承自System.Object。
2,迭代器,生成器(索引器):
迭代器:一个对象能循环,靠的是对象拥有迭代器。
谁来创造(生成)迭代器,生成器(索引器)来生成迭代器。
C#中生成器,叫成索引器
3,重要接口:
public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable
数组实现了6个接口,前4个接口很重要
ICloneable接口控制克隆,复制对象
IList列表接口,控制对象操作(添加,删除等)
IEnumerable可枚举对象的接口,控制是对象的循环
ICollection集合接口,控制复制对象
public interface IList : ICollection, IEnumerable 说明列表也是集合的一种。
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
public class List
4。集合和列表的对比:
在C#中,List
List
HashSet
数组,列表都是集合
数组不支持泛型,数组元素数据类型可以相同,也可不相同。而列表支持泛型,元素数据类型相同。
数组元素有序,列表元素也有序。
集合中元素可以有序,也可以无序。
C#中数组,ArrayList,List之间的区别: