目录
10.使用Array类中的静态方法,如Array.Sort,Array.BinarySearch 等
一.Array数组概念的简单理解
1.数组的初始化
在C#中,可以在声明数组时同时进行初始化.
数组是一种基本的数据结构,用于存储固定大小的同类型元素集合
创建数组的一般格式: 数组类型[] 数组名称=new数组类型[数组长度]
以下是常见的几种方式
代码示例:
// 一维数组初始化
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
// 简化的语法
int[] numbers2 = { 1, 2, 3, 4, 5 };
// 多维数组初始化
int[,] matrix = new int[,] { { 1, 2 }, { 3, 4 } };
// 交错数组初始化
int[][] jaggedArray = new int[][]
{
new int[] { 1, 2 },
new int[] { 3, 4, 5 }
};
在完成数组的创建后 ,可以根据数组的索引进行初始化,赋值,访问等操作
注意:数组的索引从0作为起始,以数组的长度减一作为终止
假设一个数组的长度为5
//假设一个数组的长度为5
//int[] arr = new int[5] { 1, 2, 3, 4, 5 };
int[] arr = { 1, 2, 3, 4, 5 };
//数组元素: 1 2 3 4 5
//数组索引: 0 1 2 3 4
Console.WriteLine(arr.Length); //通过Length属性获取数组的长度
Console.WriteLine(arr[3]); // 输出索引为3的元素(输出4)
arr[3]= 100; //修改数组索引为3的元素为100
//数组元素: 1 2 3 100 5
//数组索引: 0 1 2 3 4
Console.WriteLine(arr[3]);// 输出索引为3的元素(输出100)
//Console.WriteLine(arr[5]); //索引越界,如果强行进行编译,会报如下错误:
//Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
2.数组的长度
在数组中,Length属性可以获取数组的长度(即数组的元素)
代码示例:
int[] numbers = { 1, 2, 3, 4, 5 };
int length = numbers.Length; // length = 5
3.数组的克隆和复制
在数组中,可以使用Clone方法和Array.Copy方法来复制数组
代码示例:
int[] original = { 1, 2, 3, 4, 5 };
// 使用 Clone 方法
int[] clone = (int[])original.Clone();
// 使用 Array.Copy 方法
int[] copy = new int[original.Length];
Array.Copy(original, copy, original.Length);
4.数组的清空
Array.Clear方法可以将数组中所有的元素设置为默认值(比如int类型的默认值是0)
代码示例:
int[] numbers = { 1, 2, 3, 4, 5 };
Array.Clear(numbers, 0, numbers.Length); // 数组中的所有元素将变为0
5.数组的查找
在C#的数组中可以使用Array.IndexOf和Array.Find等方法去查找特定的元素
代码示例:
int[] numbers = { 1, 2, 3, 4, 5 };
// 使用 Array.IndexOf
int index = Array.IndexOf(numbers, 3); // index = 2
// 使用 Array.Find
int number = Array.Find(numbers, n => n > 3); // number = 4
6.数组的逆转
Array.Reverse方法可以翻转数组中的元素顺序
代码示例:
int[] numbers = { 1, 2, 3, 4, 5 };
Array.Reverse(numbers); // numbers = { 5, 4, 3, 2, 1 }
7.数组的拓展和缩减
在C#中一般来说Array数组的大小是在创建时固定的,一旦定义了数组就不能直接更改.
但是可以去使用Array.Resize方法去调整数组的大小
代码示例:
int[] numbers = { 1, 2, 3, 4, 5 };
Array.Resize(ref numbers, 3); // numbers = { 1, 2, 3 }
Array.Resize(ref numbers, 7); // numbers = { 1, 2, 3, 0, 0, 0, 0 }
//需要注意的是当你增加数组大小时,新增加的位置将被初始化为该类型的默认值(对于数值类型是0,对于引用类型是null)。当你减少数组大小时,超出新长度的元素将被丢弃。
8.数组的比较
为了比较两个数组是否完全相同,可以通过遍历数组元素逐个比较,或者使用SequenceEqual方法来比较两个数组是否相同.
代码示例:
int[] array1 = { 1, 2, 3 };
int[] array2 = { 1, 2, 3 };
// 使用 SequenceEqual 方法(需要 System.Linq 命名空间)
bool areEqual = array1.SequenceEqual(array2); // areEqual = true
9.数组的合并
在C#中,我们可以去使用Concat方法去合并两个数组\
代码示例:
int[] array1 = { 1, 2, 3 };
int[] array2 = { 4, 5, 6 };
// 使用 Concat 方法(需要 System.Linq 命名空间)
int[] merged = array1.Concat(array2).ToArray(); // merged = { 1, 2, 3, 4, 5, 6 }
10.使用Array类中的静态方法,如Array.Sort,Array.BinarySearch 等
代码示例:
int[] numbers = { 3, 1, 4, 5, 2 };
// 使用 Array.Sort 方法进行排序
Array.Sort(numbers); // numbers = { 1, 2, 3, 4, 5 }
// 使用 Array.BinarySearch 方法进行二分查找(前提是数组已排序)
int index = Array.BinarySearch(numbers, 4); // index = 3
二.Array数组进阶
1.二维数组
二维数组可以看作是数组的数组,即每个元素都是一个数组.例如,一个2行3列的二维数组可以看作是一个包含2个数组的数组,每个数组包含3个元素
二维数组也能够将其理解为多维数组的一种特殊形式,可以看做一个矩阵或者表格,具有行和列
// 声明一个二维数组
int[,] matrix = new int[2, 3]; // 2行3列
// 初始化一个二维数组
int[,] initializedMatrix = new int[,]
{
{ 1, 2, 3 },
{ 4, 5, 6 }
};
// 访问二维数组的元素
int element = initializedMatrix[1, 2]; // 获取第二行第三列的元素,值为6
二维数组的特点:
- 二维数组是以矩阵形式存储的
- 元素通过两个索引访问,第一个索引表示行,第二个索引表示列
- 在内存中是以行优先顺序存储的
2.多维数组
多维数组通常指代维度大于二的数组,可以用于表示更加复杂的数据结构
下面使用三维数组来举例
// 声明一个三维数组
int[,,] threeDimensional = new int[2, 3, 4]; // 2个2D数组,每个3行4列
// 初始化一个三维数组
int[,,] initializedThreeDimensional = new int[,,]
{
{
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
},
{
{ 13, 14, 15, 16 },
{ 17, 18, 19, 20 },
{ 21, 22, 23, 24 }
}
};
// 访问三维数组的元素
int element = initializedThreeDimensional[1, 2, 3]; // 获取第二个2D数组第三行第四列的元素,值为24
多维数组的特点:
- 支持多个维度,每个维度可以有不同的大小
- 通过多个索引访问元素,每个索引对应一个维度。
3.交错数组
交错数组(或锯齿数组)是数组的数组,其中每个子数组的长度可以不同.
代码示例:
// 声明一个交错数组
int[][] jaggedArray = new int[3][]; // 3个子数组
// 为每个子数组分配不同的长度
jaggedArray[0] = new int[2]; // 第一个子数组有2个元素
jaggedArray[1] = new int[3]; // 第二个子数组有3个元素
jaggedArray[2] = new int[4]; // 第三个子数组有4个元素
// 初始化交错数组
int[][] initializedJaggedArray = new int[][]
{
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6, 7, 8, 9 }
};
// 访问交错数组的元素
int element = initializedJaggedArray[1][2]; // 获取第二个子数组的第三个元素,值为5
交错数组的特点:
- 每个子数组可以有不同的长度
- 在内存中,子数组是独立的数组,可以分布在不同的位置
4.隐式类型数组
隐式类型化数组利用C#的类型推断功能,由编译器根据数组的初始值推断数组的类型.
代码示例:
// 使用隐式类型化数组
var numbers = new[] { 1, 2, 3, 4, 5 };
// 编译器推断出 numbers 是一个 int[] 类型的数组
// 对于复杂类型
var complexArray = new[]
{
new { Name = "Alice", Age = 30 },
new { Name = "Bob", Age = 25 }
};
// 编译器推断出 complexArray 是一个匿名类型数组
隐式类型数组的特点:
- 编译器根据初始值推断数组的类型,要求所有初始值的类型必须兼容
- 可以提高代码的可读性,尤其是在复杂类型的情况下
三.List集合
在C#中,List<T>是一个非常常用的泛型集合,它提供了动态数组的功能.与普通数组相比,List<T>具有更灵活的大小调整能力,并且提供了许多方便的方法来操作集合中的元素.以下是关于List<T>的详细信息:
1.基本概念
- 动态大小:List<T>可以根据需要动态调整其大小.你可以添加或移除元素,而不需要手动管理内存.
- 泛型支持:List<T>是一个泛型集合,这意味着你可以指定元素的类型,这提供了类型安全性和性能优化.
2.声明和初始化
代码示例:
// 声明一个 List<int>
List<int> numbers = new List<int>();
// 初始化一个 List<string> 并添加元素
List<string> names = new List<string> { "Alice", "Bob", "Charlie" };
3.List集合中的常用方法
- 添加元素
numbers.Add(10); // 添加单个元素 numbers.AddRange(new int[] { 20, 30, 40 }); // 添加多个元素
- 插入元素
numbers.Insert(1, 15); // 在索引1处插入元素15
- 删除元素
numbers.Remove(10); // 移除值为10的元素 numbers.RemoveAt(0); // 移除索引0处的元素 numbers.RemoveRange(0, 2); // 移除从索引0开始的两个元素
- 访问元素
int firstNumber = numbers[0]; // 访问第一个元素
- 查找元素
int index = numbers.IndexOf(30); // 查找值为30的元素的索引 bool contains = numbers.Contains(20); // 检查是否包含值为20的元素
- 排序
numbers.Sort(); // 对列表进行升序排序 numbers.Reverse(); // 反转列表顺序
- 清空列表
numbers.Clear(); // 移除所有元素
List泛型集合的特点:
- 自动扩容:List<T>内部实现为一个数组,当需要增加容量时,会自动创建一个更大的数组,并将旧数组中的元素复制到新数组中.这个过程可能会影响性能,尤其是在频繁添加大量元素时
- 索引访问:与数组类似,List<T>支持通过索引访问元素,访问速度很快
- 线程安全:List<T>不是线程安全的.在多线程环境中使用时,需要手动实现同步
List集合的应用场景 :
- 频繁更改大小的集合:List<T>非常适合需要频繁添加,删除或调整大小的集合
- 需要类型安全的集合:由于List<T>是泛型的,它可以确保集合中的所有元素都是同一类型
四.ArrayList集合
ArrayList集合:
ArrayList是 C# 中一种非泛型集合类,用于存储元素列表.它在 .NET Framework 1.0 引入,适用于早期不支持泛型的场景.尽管在现代开发中推荐使用泛型集合如List<T>,但了解 ArrayList仍然有助于理解 C# 集合的演变和处理非泛型数据的方式
1.基本概念:
- 非泛型:ArrayList可以存储任何类型的对象,因为它存储的是object类型.这意味着你可以在同一个 ArrayList中存储不同类型的数据
- 动态大小:与List<T>类似
,
ArrayList可以根据需要自动调整其大小。
2.声明和初始化
代码示例:
// 声明一个 ArrayList
ArrayList arrayList = new ArrayList();
// 初始化并添加元素
ArrayList mixedList = new ArrayList() { 1, "hello", 3.14, true };
3.ArrayList中的常用方法
- 添加元素
arrayList.Add(10); // 添加单个元素 arrayList.AddRange(new object[] { "world", 20.5 }); // 添加多个元素
- 插入元素
arrayList.Insert(1, "inserted"); // 在索引1处插入元素
- 删除元素
arrayList.Remove(10); // 移除指定值的元素 arrayList.RemoveAt(0); // 移除索引0处的元素 arrayList.RemoveRange(0, 2); // 移除从索引0开始的两个元素
- 访问元素
var firstElement = arrayList[0]; // 访问第一个元素
- 查找元素
int index = arrayList.IndexOf("hello"); // 查找元素的索引 bool contains = arrayList.Contains(3.14); // 检查是否包含某个元素
- 排序
arrayList.Sort(); // 对列表进行排序
- 清空列表
arrayList.Clear(); // 移除所有元素
性能和使用注意:
- 装箱和拆箱:由于ArrayList存储的是object类型,对于值类型(如int和double),会发生装箱和拆箱操作,可能影响性能
- 类型安全性:ArrayList不提供编译时类型检查,可能导致运行时错误.例如,尝试将不兼容的类型转换为特定类型时
- 线程安全:ArrayList不是线程安全的.在多线程环境中使用时,需要手动实现同步
应用场景:
- 早期代码:在泛型引入之前的旧代码中经常使用ArrayList
- 需要存储不同类型的集合:在某些情况下,可能需要在同一集合中存储不同类型的对象
五.总结
Array(数组)
特点 |
固定大小:数组一旦创建,其大小是固定的,不能动态调整。 类型安全:数组是强类型的,定义时需要指定元素类型,所有元素必须是同一类型。 高效访问:由于数组在内存中是连续存储的,访问速度非常快。 |
优点 |
性能高:由于连续内存分配和类型安全,数组的访问和遍历速度较快。 简单直接:适合用于已知大小和类型的集合。 |
缺点 |
大小固定:不能动态调整大小,需要预先定义。 功能有限:没有提供丰富的集合操作方法。 |
用法:
int[] numbers = new int[5]; // 创建一个长度为5的整数数组
numbers[0] = 10; // 设置元素
int first = numbers[0]; // 访问元素
List<T>
特点 |
动态大小:List<T>可以根据需要动态调整大小。 泛型支持:提供类型安全,所有元素必须是同一类型。 丰富的方法:提供了许多用于操作集合的内置方法,如添加、插入、删除、排序等。 |
优点 |
灵活性高:能够处理动态变化的集合大小。 类型安全:通过泛型提供编译时类型检查。 |
缺点 |
性能开销:在需要扩容时,会有一定的性能开销,因为需要分配新数组并复制元素。 |
用法:
List<int> numbers = new List<int>();
numbers.Add(10); // 添加元素
int first = numbers[0]; // 访问元素
ArrayList
特点 |
动态大小 非泛型:可以存储不同类型的对象,因为它存储的是object类型。 较旧的集合类型:在 .NET 1.0 时代引入,在泛型出现之前广泛使用。 |
优点 |
灵活性高:可以存储不同类型的对象。 动态调整大小:能够处理动态变化的集合大小。 |
缺点 |
类型不安全:没有编译时类型检查,可能导致运行时错误。 性能问题:由于装箱和拆箱操作,性能可能较低。 |
用法:
ArrayList arrayList = new ArrayList();
arrayList.Add(10); // 添加元素
arrayList.Add("string"); // 添加不同类型的元素
object first = arrayList[0]; // 访问元素
三者之间的异同
- 类型安全性:Array和List<T>提供类型安全,而ArrayList不提供。
- 大小调整
:
Array大小固定,List<T>和 ArrayList大小可动态调整。 - 性能:Array通常性能最好,List<T>次之,ArrayList由于装箱和拆箱可能性能最差。
- 使用场景:Array适合固定大小的集合,List<T>适合动态大小且类型一致的集合,ArrayList适合需要存储不同类型对象的旧代码。