C#——数组

        在C#中,数组是一个存储固定大小、相同类型数据的集合。数组的元素是按顺序排列的,可以通过索引来访问和修改。数组在C#中是引用类型,创建后数组的大小是固定的。

1. 数组的声明与初始化

声明数组

在 C# 中,你可以按照如下方式声明数组:

// 声明一个整数数组
int[] numbers;
初始化数组

数组有多种初始化方式:

// 初始化一个包含5个元素的整数数组
int[] numbers = new int[5]; 

// 初始化时指定元素
int[] numbers2 = new int[] { 1, 2, 3, 4, 5 }; 

// 简化的初始化语法
int[] numbers3 = { 1, 2, 3, 4, 5 }; 

2. 访问数组元素

数组的元素可通过索引来访问,索引从 0 开始:

int[] numbers = { 1, 2, 3, 4, 5 };
int firstNumber = numbers[0]; // 访问第一个元素
numbers[2] = 10; // 修改第三个元素的值

3. 多维数组

C# 支持多维数组,常见的有多维数组和交错数组。

多维数组
// 声明并初始化一个二维数组
int[,] matrix = new int[3, 3] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
int element = matrix[1, 2]; // 访问第二行第三列的元素
交错数组
// 声明并初始化一个交错数组
int[][] jaggedArray = new int[3][];
jaggedArray[0] = new int[] { 1, 2 };
jaggedArray[1] = new int[] { 3, 4, 5 };
jaggedArray[2] = new int[] { 6 };

4. 数组的属性和方法

数组的属性
  • Length:获取数组的元素总数。
int[] numbers = { 1, 2, 3, 4, 5 };
int length = numbers.Length; // 获取数组的长度

5. 数组的遍历

使用 for 循环或 foreach 循环遍历数组。

int[] numbers = { 1, 2, 3, 4, 5 };

// 使用 for 循环遍历数组
for (int i = 0; i < numbers.Length; i++)
{
    Console.WriteLine(numbers[i]);
}

// 使用 foreach 循环遍历数组
foreach (int number in numbers)
{
    Console.WriteLine(number);
}

6. 作为方法参数传递数组

数组可以作为参数传递给方法。

void PrintArray(int[] arr)
{
    foreach (int num in arr)
    {
        Console.WriteLine(num);
    }
}

int[] numbers = { 1, 2, 3, 4, 5 };
// 调用方法并传递数组
PrintArray(numbers); 

7. 数组的复制

可以使用 Array.Copy 方法或 Clone 方法复制数组。

int[] source = { 1, 2, 3, 4, 5 };
int[] destination = new int[source.Length];

// 使用 Array.Copy 方法复制数组
Array.Copy(source, destination, source.Length);

// 使用 Clone 方法复制数组
int[] cloneArray = (int[])source.Clone();

8. 数组协变

在 C# 中,引用类型的数组支持协变,即派生类数组可以隐式转换为基类数组,但这在值类型数组中不适用。

class Animal { }
class Dog : Animal { }

Dog[] dogs = new Dog[3];
// 数组协变,Dog 数组可以隐式转换为 Animal 数组
Animal[] animals = dogs; 

9. 数组的声明和初始化拓展

基于常量表达式的数组大小声明

在 C# 中,数组声明时大小可以基于常量表达式。

const int size = 5;
int[] arrayWithConstSize = new int[size];

10. 数组元素访问和修改的注意事项

边界检查的重要性

访问数组元素时,索引必须在有效范围内,否则会抛出 IndexOutOfRangeException。在处理动态索引时,要严格检查边界。

int[] arr = { 1, 2, 3 };
int index = 5;
if (index >= 0 && index < arr.Length)
{
    int value = arr[index];
}
else
{
    Console.WriteLine("索引超出范围");
}

11. 数组与其他数据结构的交互

数组转换为集合

可以将数组转换为 List 等集合类型,方便进行动态操作。

int[] array = { 1, 2, 3 };
List list = new List(array);
集合转换为数组

同样,也能把集合转换为数组。

List stringList = new List { "a", "b", "c" };
string[] stringArray = stringList.ToArray();

12. 字符串分割

// 按单个字符分割
string inputSingle = "apple,banana,orange";
string[] fruitsSingle = inputSingle.Split(',');

// 按多个字符分割
string inputMulti = "apple,banana;orange";
char[] separators = { ',', ';' };
string[] fruitsMulti = inputMulti.Split(separators);

// 按字符串分割
string inputStr = "apple---banana---orange";
string[] fruitsStr = inputStr.Split(new string[] { "---" }, StringSplitOptions.None); // StringSplitOptions.None表示不忽略空字符串

13. 字符串拼接

// 使用 + 运算符
string part1 = "Hello";
string part2 = " World";
string resultPlus = part1 + part2;

// 使用 string.Concat 方法
string resultConcat = string.Concat(part1, part2);

// 使用 string.Join 方法
string[] words = { "Hello", "World" };
string resultJoin = string.Join(" ", words);

// 使用 StringBuilder 类
StringBuilder sb = new StringBuilder();
sb.Append("Hello");
sb.Append(" ");
sb.Append("World");
string resultSB = sb.ToString();

14. 字符串替

// 简单替换
string inputReplace = "Hello World";
string resultSimpleReplace = inputReplace.Replace("World", "C#");

// 忽略大小写替换
string inputCase = "Hello WoRlD";
string pattern = "world";
string resultCaseReplace = Regex.Replace(inputCase, pattern, "C#", RegexOptions.IgnoreCase);

15. 数组的特性

1)固定大小:数组在初始化时需要指定大小,一旦创建,大小无法更改。

2)元素类型相同:数组中的所有元素必须是相同类型。

3)零索引:数组的索引从 0 开始,最后一个元素的索引为 Length - 1。

16. 参数数组

        使用params关键字定义一个可变参数数组,允许在调用方法时传递任意数量的参数。使用 params时,可以向方法传递一个数组,或者直接传递多个值,编译器会自动将它们转换为数组。params参数使得方法更加灵活,不需要提前指定固定数量的参数。这对于处理动态数量的输入参数非常有用。

        params关键字只能用于方法的最后一个参数,并且该参数必须是一个数组类型。表示可以传入一个数组,或者直接传入多个参数。

using System;

class Program
{
    // 定义一个使用 params 关键字的方法
    public static void PrintNumbers(params int[] numbers)
    {
        if (numbers.Length == 0)
        {
            Console.WriteLine("没有传递任何数字。");
        }
        else
        {
            Console.Write("传递的数字是: ");
            foreach (int num in numbers)
            {
                Console.Write(num + " ");
            }
            Console.WriteLine();
        }
    }

    // 实现求和方法
    public static int Sum(params int[] numbers)
    {
        int sum = 0;
        foreach (int number in numbers)
        {
            sum += number;
        }
        return sum;
    }

    static void Main()
    {
        // 直接传递多个值
        PrintNumbers(1, 2, 3, 4, 5);
        // 传递数组
        int[] numArray = { 6, 7, 8 };
        PrintNumbers(numArray);
        // 不传递参数
        PrintNumbers();

        // 求和方法调用
        Console.WriteLine("Sum(1, 2, 3) 的结果: " + Sum(1, 2, 3));
        Console.WriteLine("Sum(10, 20, 30, 40) 的结果: " + Sum(10, 20, 30, 40));
        Console.WriteLine("Sum() 的结果: " + Sum());
    }
}    

17. params 与方法重载的优先级问题

        当存在方法重载时,C# 编译器会优先选择最匹配的方法,而不是使用 params 版本的方法。例如:

using System;

class Program
{
    public static void Print(int a)
    {
        Console.WriteLine("调用了单参数 Print 方法: " + a);
    }

    public static void Print(params int[] values)
    {
        Console.Write("调用了 params 版本的 Print 方法: ");
        foreach (var value in values)
        {
            Console.Write(value + " ");
        }
        Console.WriteLine();
    }

    static void Main()
    {
        Print(1); // 会调用单参数的 Print 方法
        Print(1, 2, 3); // 会调用 params 版本的 Print 方法
    }
}

        在上述代码中,当调用 Print(1) 时,编译器会优先选择单参数的 Print 方法;当调用 Print(1, 2, 3) 时,由于没有匹配的方法,才会调用 params 版本的 Print 方法。

18. params 在委托中的使用

params 关键字也可以在委托中使用,以下是一个示例:

using System;

// 定义一个使用 params 关键字的委托
delegate void PrintNumbersDelegate(params int[] numbers);

class Program
{
    public static void PrintNumbers(params int[] numbers)
    {
        Console.Write("委托调用,传递的数字是: ");
        foreach (int num in numbers)
        {
            Console.Write(num + " ");
        }
        Console.WriteLine();
    }

    static void Main()
    {
        PrintNumbersDelegate del = PrintNumbers;
        del(1, 2, 3);
        int[] arr = { 4, 5, 6 };
        del(arr);
    }
}

        在这个示例中,定义了一个使用 params 关键字的委托 PrintNumbersDelegate,并将 PrintNumbers 方法赋值给该委托,然后可以像调用普通方法一样使用委托,支持直接传递多个值或数组。

19. 数组排序和数组反转

using System;

class Program
{
    static void Main()
    {
        // 定义一个数组
        int[] arr = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };

        // 数组排序
        Array.Sort(arr);
        Console.Write("排序后的数组: ");
        foreach (int num in arr)
        {
            Console.Write(num + " ");
        }
        Console.WriteLine();

        // 数组反转
        Array.Reverse(arr);
        Console.Write("反转后的数组: ");
        foreach (int num in arr)
        {
            Console.Write(num + " ");
        }
    }
}

20. 值类型变量和引用类型变量

待补充

你可能感兴趣的:(c#,算法,数据结构)