龙空技术网

C# 数据结构和算法 :03 数组和排序(一)

启辰8 18

前言:

此时看官们对“如何初始化二维数组的数据格式”大约比较看重,姐妹们都想要知道一些“如何初始化二维数组的数据格式”的相关文章。那么小编也在网上搜集了一些有关“如何初始化二维数组的数据格式””的相关文章,希望我们能喜欢,看官们快快来学习一下吧!

作为开发者,你肯定已经在你的应用程序中存储了各种各样的集合,比如用户数据、书籍和日志。存储此类数据的一种自然方式是使用数组。然而,你是否考虑过它们的变体?例如,你听说过不规则数组吗?在本章中,你将看到数组的实际应用,包括示例和详细描述。

你可以使用数组来存储许多相同类型的项目,如 int、string,以及用户定义的类或记录。只要记住,在初始化后,数组中的元素数量不能改变。因此,你将无法轻松地在数组末尾添加一个新项目,或者在数组中的给定位置插入一个元素,同时将剩余的项目向前移动一个位置。如果你需要这样的功能,你可以使用另一种数据结构,即列表及其变体,这将在下一章中描述。

在使用C#语言开发应用程序时,你可以利用数组的几种变体,即单维数组、多维数组和不规则数组。在本章中,你还将了解到七种排序算法,分别是选择排序、插入排序、冒泡排序、归并排序、Shell排序、快速排序和堆排序。对于每一种,你将看到一个基于图解的示例、实现代码以及逐步解释。你还将看到它们的性能分析,通过图表展示。

本章将涵盖以下主题:

• 单维数组

• 多维数组

• 不规则数组

• 排序算法

单维数组

让我们从数组中最简单的变体开始,即单维数组。这样的数组存储了一组相同类型的项目,可以通过索引来访问。重要的是要记住,在C#中数组元素的索引是从零开始的。这意味着第一个元素的索引等于0,而最后一个元素的索引等于数组长度减一。

想象一个单维数组

如果你想更好地想象一个单维数组,暂时把目光从这本书上移开,看看你房间里的五斗橱或衣柜。一个标准的五斗橱由几个抽屉组成,单维数组看起来也很相似。它也有几个元素(像抽屉一样),可以通过索引来访问。你不能像改变抽屉数量那样改变数组的大小,因为家具已经准备好了。数组有一个显著的优势,那就是它的所有“抽屉”总是按预期工作。

下面的图中显示了一个单维数组的例子:

它包含五个元素,其值分别为:9, -11, 6, -12, 和 1。第一个元素的索引等于0,而最后一个元素的索引等于4。

要使用一维数组,你需要声明并初始化它。声明非常简单,因为你只需要指定元素类型和一个名称,如下所示:

type[] name;

数组的声明,其中包含整数值,如下所示:

int[] numbers;

到目前为止,你知道如何声明一个数组,但是关于初始化呢?要创建一个有五个元素的数组并将其初始化为默认值,你可以使用new操作符,如下所示:

numbers = new int[5];

当然,你可以在同一行中结合声明和初始化,如下所示:

int[] numbers = new int[5];

不幸的是,目前所有元素都具有默认值——即整数值的情况下为零。因此,你需要设置特定元素的值。你可以使用[]操作符和元素的索引来完成这个操作,如下所示的代码:

numbers[0] = 9;numbers[1] = -11;numbers[2] = 6;numbers[3] = -12;numbers[4] = 1;

此外,你可以使用以下几种方式之一,将数组元素的声明和初始化与特定值结合起来:

int[] numbers = new int[] { 9, -11, 6, -12, 1 };int[] numbers = { 9, -11, 6, -12, 1 };

另一种方法涉及使用集合表达式,如下所示:

int[] numbers = [9, -11, 6, -12, 1];

当你拥有数组内元素的适当值时,你可以使用[]操作符并通过指定索引来获取值,如下行代码所示:

int middle = numbers[2];

在这里,你获取数组numbers中第三个元素(索引等于2)的值,并将其存储为中间变量的值。

数组具有一些在开发应用程序时可能有用的属性。例如,Length属性使得获取数组的大小成为可能,即存储在其中的元素数量。如果你想访问数组中的最后一个项目,无论其大小如何,你可以使用以下代码行:

int last = numbers[numbers.Length - 1];

你可以使用索引运算符来简化如下:

int last = numbers[^1];

值得注意的是,倒数第二个项目可以通过[^2]接收,第三个可以通过[^3]接收,以此类推。

另一个属性名为Rank,返回数组的维度数量。这个属性的使用示例如下一行代码所示:

int rank = numbers.Rank;

除了已经提到的属性之外,你还可以使用Array类的一系列静态方法,比如Exists,来检查数组中是否有任何元素匹配给定的谓词。例如,你可以轻松验证数组是否包含任何值大于零的元素,如下所示:

bool anyPositive = Array.Exists(numbers, e => e > 0);

除了其他方法,你可以使用TrueForAll来检查所有元素是否满足提供的谓词,例如确保数组中没有零:

bool noZeros = Array.TrueForAll(numbers, e => e != 0);

你也可以获取第一个匹配谓词的元素。举个例子,让我们使用Find方法来获取第一个小于零的数字的值:

int firstNegative = Array.Find(numbers, e => e < 0);

如果你想要得到一个包含所有满足给定条件的元素的新数组,你可以使用FindAll方法。以下代码展示了如何获取所有负数:

int[] negatives = Array.FindAll(numbers, e => e < 0);

当你不想指定谓词,只是想检查数组是否包含给定元素时,你可以使用IndexOf方法,它会返回找到的第一个值的索引,如果没有找到则返回-1:

int index = Array.IndexOf(numbers, -12);

另一个有趣的静态方法是ForEach。它允许你对数组中的所有元素执行一些操作。例如,你可以使用它将每个数组元素的绝对值写入控制台,如下所示的代码:

Array.ForEach(numbers,  e => Console.WriteLine(Math.Abs(e)));

正如你所见,即使是对于像单维数组这样简单的数据结构,你也有许多有用的内置功能。让我们继续学习它们,并看看接下来的两个方法,即 Reverse 和 Sort。顾名思义,第一个允许你反转元素的顺序,无论是整个数组还是仅在某个范围内。这在下面的代码行中有所体现,它反转了前三个元素:

Array.Reverse(numbers, 0, 3);

排序方法有更多变体。在其最简单的形式中,它会排序整个数组。运行以下代码后,你会得到一个数组,其元素从小到大排序:

Array.Sort(numbers);

如果你想用相同的值填充整个数组,或者填充一系列元素的相同值,你可以使用一个for循环,简单地遍历适当的索引并赋给一个给定的值。然而,你也可以使用Fill方法。以下这行代码将3作为数组所有元素的值。

Array.Fill(numbers, 3);

我们可以使用的另一种方法是Clear,它使得清除整个数组或其元素的范围成为可能。例如,你可以使用以下代码行将整个数组填充为整数类型的默认值,即零:

Array.Clear(numbers);

现在,让我们来看看Copy函数,它从源数组复制一系列元素到目标数组。你可以使用几种变体中的一个,比如指定两个数组的索引。举个例子,让我们从numbers数组(作为源数组)复制3个元素(以长度指定),从第一个元素开始(源索引设置为0),并将它们放置在subarray数组中,从第一个元素开始(目标索引设置为0)://

int[] subarray = new int[3];Array.Copy(numbers, 0, subarray, 0, 3);

我们已经介绍了一些可用的属性和方法,但值得一提的还有一些扩展方法,比如Contains和Max。

你听说过扩展方法吗?

如果没有,可以把它们想象成是“添加”到特定现有类型(无论是内置的还是用户定义的)的方法,并且可以像定义为实例方法时一样直接调用它们。扩展方法的声明需要你在静态类中指定它作为一个静态方法,并且第一个参数使用this关键字来指示你想要“添加”这个方法的类型。

你可以使用Contains扩展方法来检查数组是否包含作为参数传递的元素。作为示例,让我们学习如何确保numbers数组包含6作为其元素之一:

bool contains = numbers.Contains(6);

Contains方法并不是唯一可用的扩展方法。在其他方法中,你可以找到All和Any。第一个(All)检查所有元素是否符合给定的谓词,而另一个(Any)验证是否至少有一个元素满足条件。你可以使用它们来确保数组中没有零,并检查是否至少有一个正数元素,如下所示:

bool noZeros = numbers.All(n => n != 0);bool anyPositive = numbers.Any(n => n > 0);

你将如何找到数组中的最小值或最大值?你可能会遍历所有元素,并检查每个元素是否比已经找到的最小值或最大值更小(寻找最小值时)或更大(寻找最大值时)。如果这是你的解决方案,你是正确的,这是一个解决问题的好方法。然而,你可以通过使用Min和Max扩展方法来使你的代码更简洁,如下所示:

int min = numbers.Min();int max = numbers.Max();

挺简单的,对吧?我们再来看看Average和Sum方法,它们可以轻松计算出所有元素的平均值以及它们的总和:

double avg = numbers.Average();int sum = numbers.Sum();

在对一维数组进行了简短的介绍之后,现在是时候看看如何在现实场景中应用这样的数组了。

示例 - 月份名称

为了总结您对一维数组所学到的知识,让我们使用一个数组来存储用英文写的月份名称。这些名称应该自动获取,而不是在代码中硬编码。

using System.Globalization;CultureInfo culture = new("en");string[] months = new string[12];for (int month = 1; month <= 12; month++){    DateTime firstDay = new(DateTime.Now.Year, month, 1);    string name = firstDay.ToString("MMMM", culture);    months[month - 1] = name;}foreach (string m in months){    Console.WriteLine(m);}

首先,您需要创建一个新的CultureInfo类实例(来自System.Globalization命名空间),将"en"作为参数传递,以便稍后获取英文月份名称。然后,声明一个新的单维数组并用默认值进行初始化。它包含12个元素,用于存储一年中所有月份的名称。然后,使用for循环遍历所有月份的数字——即从1到12。对于每一个数字,都会创建一个表示当前年份中特定月份第一天的DateTime实例。

通过在DateTime实例上调用ToString方法,并传入正确的日期格式(MMMM)以及指定文化信息,可以获取月份的名称。然后,使用[]操作符和元素的索引来将名称存储在数组中。值得注意的是,索引等于月份变量的当前值减一。这种减法是必要的,因为数组的第一个元素的索引等于零,而不是一。

代码的下一个有趣部分是foreach循环,它遍历数组中的所有元素。对于每一个元素,都会在控制台中显示月份的名称:

JanuaryFebruary (...)December

如前所述,单维数组并不是唯一可用的变体。在接下来的部分,你将学习更多关于多维数组的知识。

标签: #如何初始化二维数组的数据格式