C#中的数组
C#中的数组介绍
在 C# 中,数组是一种数据结构,用于存储固定大小的相同类型的元素集合。数组可以是一维的,也可以是多维的(例如二维、三维等)。数组在声明时必须指定元素的类型,并且一旦创建,其大小就是固定的。
一维数组
一维数组是最基础的数组形式,它包含一个元素序列。
声明和初始化一维数组:
int[] array = new int[5]; // 创建一个包含5个整数的数组,初始值默认为0
array[0] = 10;
array[1] = 20;
// ...
// 直接初始化
int[] array2 = { 10, 20, 30, 40, 50 };
多维数组
多维数组可以视为数组的数组,例如二维数组可以视为行和列的集合。
声明和初始化二维数组:
int[,] array2D = new int[3, 4]; // 创建一个3行4列的二维整数数组
array2D[0, 0] = 1;
array2D[0, 1] = 2;
// ...
// 直接初始化
int[,] array2D = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
数组的特性
-
长度:数组有一个
Length
属性,它返回数组中元素的总数。 -
固定大小:数组的大小在创建后不能改变。
-
零基索引:数组的索引从 0 开始。
-
类型安全:数组的元素必须是声明时指定的类型或其派生类型。
数组的方法
数组类型 System.Array
提供了一些有用的方法,例如:
-
Clone()
:创建数组的浅表副本。 -
CopyTo()
:将数组的元素复制到另一个数组。 -
Resize()
:改变数组的大小(需要System.Collections.Generic
命名空间中的List<T>
类)。
遍历数组
可以使用 for
循环或 foreach
循环来遍历数组中的所有元素。
使用 for 循环:
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
使用 foreach 循环:
foreach (int element in array)
{
Console.WriteLine(element);
}
数组的内存管理
数组是引用类型,它们在托管堆上分配内存。当数组不再被引用时,它们会成为垃圾回收的候选对象。
C#中的数组的常用方法
在 C# 中,数组是内置的数据结构,提供了一些常用的方法来操作数组。这些方法大多数定义在 System.Array
类中,该类是所有数组类型的基类。以下是一些常用的数组方法:
-
Clone():
-
创建数组的浅表副本。
int[] original = { 1, 2, 3 }; int[] copy = (int[])original.Clone();
-
-
CopyTo(Array array, int index):
-
将当前数组中的元素复制到另一个数组中。
int[] source = { 1, 2, 3 }; int[] destination = new int[5]; Array.Copy(source, destination, 3);
-
-
Clear():
-
将数组的所有元素设置为其类型的默认值。
int[] array = { 1, 2, 3 }; Array.Clear(array, 0, array.Length);
-
-
Resize():
-
改变数组的大小。这需要
System.Collections.Generic.List<T>
类,而不是System.Array
。
int[] array = { 1, 2, 3 }; Array.Resize(ref array, 5); // 将数组大小改为 5
-
-
Sort():
-
对数组进行排序。
int[] array = { 3, 1, 4, 2 }; Array.Sort(array);
-
-
BinarySearch():
-
在已排序的数组中进行二进制搜索。
int[] array = { 1, 2, 3, 4, 5 }; int index = Array.BinarySearch(array, 3); // 返回 2
-
-
IndexOf():
-
返回数组中特定值的第一个匹配项的索引。
int[] array = { 1, 2, 3, 4, 5 }; int index = Array.IndexOf(array, 3); // 返回 2
-
-
LastIndexOf():
-
返回数组中特定值的最后一个匹配项的索引。
int[] array = { 1, 2, 3, 4, 3 }; int index = Array.LastIndexOf(array, 3); // 返回 4
-
-
Reverse():
-
反转数组中元素的顺序。
int[] array = { 1, 2, 3, 4, 5 }; Array.Reverse(array);
-
-
Exists():
-
检查数组中是否存在满足特定条件的元素。
int[] array = { 1, 2, 3, 4, 5 }; bool exists = Array.Exists(array, x => x > 3); // 返回 true
-
-
Find():
-
返回数组中满足特定条件的第一个元素。
int[] array = { 1, 2, 3, 4, 5 }; int found = Array.Find(array, x => x > 3); // 返回 4
-
-
ForEach():
-
对数组中的每个元素执行指定的操作。
int[] array = { 1, 2, 3, 4, 5 }; Array.ForEach(array, x => Console.WriteLine(x));
-
C#中的二维数组和交叉数组
在 C# 中,二维数组和交叉数组(Jagged Array)都是用于存储多个数组的数组,但它们在内存布局和性能方面有所不同。
二维数组
二维数组可以看作是数组的数组,其中的每个数组(称为子数组)都具有相同的长度,类似于数学中的矩阵。二维数组在内存中是连续存储的。
声明和初始化二维数组:
int[,] twoDArray = new int[5, 10]; // 5 行 10 列的二维数组
twoDArray[0, 0] = 1;
twoDArray[0, 1] = 2;
// ...
// 直接初始化
int[,] twoDArray = {
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
// ...
};
交叉数组
交叉数组是数组的数组,其中的每个数组(称为子数组)可以具有不同的长度,因此它在内存中不是连续存储的。交叉数组在处理不同长度的子数组时更加灵活。
声明和初始化交叉数组:
int[][] jaggedArray = new int[5][]; // 5 个未初始化的子数组
jaggedArray[0] = new int[10];
jaggedArray[1] = new int[20];
// ...
// 直接初始化
int[][] jaggedArray = {
new int[] { 1, 2, 3, 4, 5 },
new int[] { 6, 7, 8, 9, 10, 11, 12 },
// ...
};
性能考虑
-
内存使用:二维数组在内存中是连续存储的,这可能在某些情况下导致内存浪费,尤其是当数组的某些行或列没有被完全使用时。交叉数组则可以根据需要为每个子数组分配确切的内存,从而节省内存。
-
性能:二维数组由于在内存中连续存储,因此在访问时可能具有更好的性能,因为 CPU 缓存可以更有效地工作。交叉数组由于其非连续性,可能在访问时性能稍差。
选择使用
-
如果所有子数组的长度都相同,并且对性能有较高要求,可以选择使用二维数组。
-
如果子数组的长度不同,或者需要动态地调整子数组的大小,交叉数组是更好的选择。
## 在 C# 中,二维数组和交叉数组(Jagged Array)都是用于存储多个数组的数组,但它们在内存布局和性能方面有所不同。
二维数组
二维数组可以看作是数组的数组,其中的每个数组(称为子数组)都具有相同的长度,类似于数学中的矩阵。二维数组在内存中是连续存储的。
声明和初始化二维数组:
int[,] twoDArray = new int[5, 10]; // 5 行 10 列的二维数组
twoDArray[0, 0] = 1;
twoDArray[0, 1] = 2;
// ...
// 直接初始化
int[,] twoDArray = {
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
// ...
};
交叉数组
交叉数组是数组的数组,其中的每个数组(称为子数组)可以具有不同的长度,因此它在内存中不是连续存储的。交叉数组在处理不同长度的子数组时更加灵活。
声明和初始化交叉数组:
int[][] jaggedArray = new int[5][]; // 5 个未初始化的子数组
jaggedArray[0] = new int[10];
jaggedArray[1] = new int[20];
// ...
// 直接初始化
int[][] jaggedArray = {
new int[] { 1, 2, 3, 4, 5 },
new int[] { 6, 7, 8, 9, 10, 11, 12 },
// ...
};
性能考虑
-
内存使用:二维数组在内存中是连续存储的,这可能在某些情况下导致内存浪费,尤其是当数组的某些行或列没有被完全使用时。交叉数组则可以根据需要为每个子数组分配确切的内存,从而节省内存。
-
性能:二维数组由于在内存中连续存储,因此在访问时可能具有更好的性能,因为 CPU 缓存可以更有效地工作。交叉数组由于其非连续性,可能在访问时性能稍差。
选择使用
-
如果所有子数组的长度都相同,并且对性能有较高要求,可以选择使用二维数组。
-
如果子数组的长度不同,或者需要动态地调整子数组的大小,交叉数组是更好的选择。
数组和集合的区别
在 C# 中,数组和集合是两种不同的数据结构,它们在用途、功能和性能方面有显著的区别。以下是数组和集合的主要区别:
数组(Array)
-
固定大小:数组在声明时必须指定大小,一旦创建,其大小就固定不变。
-
类型安全:数组是强类型数据结构,即数组的每个元素都必须是相同的数据类型。
-
性能:数组通常在内存中连续存储,这使得数组访问速度快,但缺乏灵活性。
-
索引访问:数组通过索引访问元素,索引从 0 开始。
-
简单性:数组结构简单,适用于存储同类型数据的简单集合。
-
内置支持:C# 提供了丰富的数组操作方法,如
Array.Sort()
、Array.Resize()
等。
集合(Collection)
-
动态大小:集合(如
List<T>
、Dictionary<TKey, TValue>
等)的大小是动态的,可以根据需要增长和缩小。 -
灵活性:集合提供了更多的功能,如添加、删除、插入和搜索元素等。
-
泛型支持:集合通常支持泛型,这意味着你可以创建一个集合来存储任何类型的数据。
-
非连续存储:集合元素在内存中可能不是连续存储的,这使得它们在添加和删除元素时更加灵活,但可能影响性能。
-
丰富的数据结构:集合包括列表、队列、堆栈、字典等多种数据结构,每种结构都有其特定的用途和操作。
-
LINQ 支持:集合与语言集成查询(LINQ)紧密集成,使得数据操作更加方便。
示例
-
数组:
int[] numbers = new int[5]; // 创建一个大小为 5 的整型数组 numbers[0] = 10; numbers[1] = 20;
-
集合(例如 List<T>):
List<int> numbers = new List<int>(); // 创建一个整型列表 numbers.Add(10); numbers.Add(20); numbers.Add(30); // 可以动态添加元素
选择使用
-
使用数组:当你需要存储固定数量的同类型数据,且对性能有较高要求时,可以选择数组。
-
使用集合:当你需要一个灵活的数据结构,可以动态地添加、删除或搜索数据时,集合是更好的选择。
总结来说,数组和集合各有优势,选择使用哪一个取决于你的具体需求,包括数据的大小、类型、操作的复杂性以及性能要求。