跳到内容

数据结构/数组

来自维基教科书,开放世界中的开放书籍

数组是一种集合,主要由类似的数据类型组成,存储在一个公共变量中。该集合构成一个数据结构,其中对象以线性方式存储,一个接一个地存储在内存中。有时数组甚至会被复制到内存硬件中。

该结构也可以定义为存储索引数据的元素的特定方法。数据元素在数组中以块的形式逻辑上按顺序存储。每个元素都通过一个索引或下标来引用。

索引通常是一个用于寻址数组中元素的数字。例如,如果你要存储关于八月份每一天的信息,你会创建一个索引能够寻址 31 个值的数组——八月份每个日期对应一个值。索引规则依赖于语言,但是大多数语言使用 0 或 1 作为数组的第一个元素。

对于初学者来说,数组的概念可能令人望而生畏,但实际上它非常简单。想象一本从 1 到 12 编页的笔记本。每个页面可能包含或不包含信息。笔记本是一个包含页面的数组。每个页面都是'笔记本'数组的元素。在编程中,你会通过引用页面的编号或下标来检索页面上的信息,例如,notebook(4) 将引用数组 notebook 中第 4 页的内容。


笔记本(数组)包含 12 页(元素)

数组也可以是多维的——而不是访问一维列表的元素,元素可以通过两个或多个索引访问,例如矩阵或张量。

多维数组就像我们上面提到的笔记本示例一样简单。要想象一个多维数组,可以考虑一个日历。日历的每一页,从 1 到 12,是一个元素,代表一个月,包含大约 30 个元素,代表天数。每一天可能包含或不包含信息。然后在编程中,calendar(4,15) 将引用第 4 个月第 15 天。因此我们有一个二维数组。要想象一个三维数组,可以将每一天分成 24 个小时。现在 calendar(4,15,9) 将引用第 4 个月第 15 天第 9 小时。


一个简单的 6 行 4 列数组

Array<Element> 操作

make-array(整数 n): 数组

创建一个索引从 (包含)的元素的数组。数组中元素的数量,也称为数组的大小,是 n

get-value-at(Array a, 整数 index): 元素

返回给定index处的元素的值。index的值必须在范围内:0 <= index <= (n - 1)。此操作也称为下标

set-value-at(Array a, 整数 index, 元素 new-value)

将数组中给定index处的元素设置为等于new-value

数组保证恒定时间读写访问,,但是元素实例的许多查找操作(find_min、find_max、find_index)是线性时间,。数组在大多数语言中非常有效,因为操作通过基于数组的基地址元素的简单公式计算元素的地址。

数组的实现方式在不同语言之间存在很大差异:一些语言允许数组自动调整大小,甚至包含不同类型的元素(如 Perl)。其他语言则非常严格,要求在运行时知道数组的类型和长度信息(如 C)。

数组通常直接映射到计算机内存中的连续存储位置,因此是大多数高级语言的“自然”存储结构。

简单的线性数组是大多数其他数据结构的基础。许多语言不允许你分配除了数组以外的任何结构,所有其他结构必须在数组之上实现。唯一的例外是链表,它通常实现为单独分配的对象,但也可以在数组中实现链表。

数组索引需要某种类型。通常,使用该语言的标准整数类型,但也有像 AdaPascal 这样的语言,允许任何离散类型作为数组索引。脚本语言通常允许任何类型作为索引(关联数组)。

数组索引由一个具有下界和上界的数值范围组成。

在一些编程语言中,只有上界可以选择,而下界固定为 0 (CC++C#Java) 或 1 (FORTRAN 66R)

在其他编程语言中 (AdaPL/IPascal),下界和上界都可以自由选择 (甚至可以为负数)

边界检查

[编辑 | 编辑源代码]

数组索引的第三个方面是检查有效范围以及访问无效索引时会发生什么。这是一个非常重要的点,因为大多数 计算机蠕虫计算机病毒 都是通过使用无效的数组边界来攻击的。

有三种选择

  1. 大多数语言 (AdaPL/IPascalJavaC#) 将检查边界,并在访问不存在的元素时引发某种错误条件。
  2. 少数语言 (CC++) 不会检查边界,并在访问超出有效范围的元素时返回或设置某个任意值。
  3. 脚本语言通常在将数据写入之前无效的索引时自动扩展数组。

声明数组类型

[编辑 | 编辑源代码]

数组类型的声明取决于特定语言中数组具有的特性数量。

最简单的声明是在语言具有固定下界和固定索引类型的情况下。如果需要一个数组来存储月收入,可以在 C 中声明

typedef double Income[12];

这将提供一个范围为 0 到 11 的数组。有关 C 中数组的完整描述,请参阅 C 编程/数组

如果使用的是可以同时选择下界和索引类型的语言,那么声明当然会更加复杂。以下是在 Ada 中的两个示例

type Month is range 1 .. 12;
type Income is array(Month) of Float;

或更短的

type Income is array(1 .. 12) of Float;

有关 Ada 中数组的完整描述,请参阅 Ada 编程/类型/数组

数组访问

[编辑 | 编辑源代码]

我们通常使用名称、后跟括号(方括号“[]”或圆括号“()”)中的索引来写数组。例如,August[3]是 C 编程语言中用来引用一个月中特定日期的方法。

因为 C 语言从零开始索引,August[3]是数组中的第 4 个元素。august[0]实际上引用的是该数组的第一个元素。从零开始索引对于计算机来说是自然的,因为它们的内部数字表示从零开始,但对于人类来说,这种非自然的编号系统在访问数组中的数据时会导致问题。在使用基于零索引的语言获取元素时,请牢记数组的实际长度,以免获取错误的数据。这是在使用具有固定下界的语言编程时的缺点,程序员必须始终记住“[0]”表示“第一个”,并在需要时添加或减去 1。具有可变下界的语言将减轻程序员的负担。

我们使用索引来存储相关数据。如果我们的 C 语言数组名为august,并且我们希望存储我们将在第一天去超市的信息,我们可以说,例如

august[0] = "Going to the shops today"

这样,我们可以遍历索引 0 到 30,获取每个日期的相应任务。august.

华夏公益教科书