1.4 读取
首先来看读取操作。读取操作可以检查数组内某一索引处的值。
计算机从数组中读取仅需要1步。这是因为计算机有能力跳到任意索引的位置,并检查它的值。在["apples", "bananas", "cucumbers", "dates", "elderberries"]
这个数组中,如果要检查索引2,那么计算机就会立刻跳转到索引2,并报告它的值"cucumbers"
。
为什么检查数组的索引只需要1步呢?原因如下。
计算机的内存就像一大堆格子。在下图中,你可以看到一堆格子,有些是空的,有些包含数据。
虽然这只是计算机内存工作原理的简化示意图,但其本质的确如此。
当程序声明数组时,会分配一段连续的空格子供其使用。如果你要创建一个存储5个元素的数组,那么计算机就会找5个连续的空格子,作为数组使用,如下图所示。
计算机内存的每个格子都有一个地址。这有点儿像街道地址(比如中央大街123号),但它是用数字表示的。每个格子的内存地址都比前一个格子大1,如下图所示。
下图给出了购物清单数组的索引和内存地址。
当计算机读取数组中某一索引的值时,能直接跳转到那个索引,因为它具有如下特性。
(1) 计算机可以一步跳转到任意内存地址。如果让计算机检查内存地址1063存储的数据,那么无须做任何搜索它就能直接读取那个值。打个比方,如果我叫你伸出右手小拇指,那么不需要搜索所有手指你也知道是哪一根。你马上就能找到它。
(2) 当计算机将内存分配给数组时,它会记录数组从哪个内存地址开始。如果让计算机寻找数组的第一个元素,那么它立刻就能跳转到对应的内存地址并找到它。
这两点解释了为什么计算机只用1步就能找到数组的第一个值。计算机只要再做一个简单的加法,就能找到任意索引的值。如果让计算机寻找索引3的值,那么它只需在索引0的内存地址上加3即可。(毕竟内存地址是连续的。)
下面以购物清单数组为例。这个数组开始于内存地址1010。如果让计算机读取索引3的值,它就会经历如下过程。
(1) 数组开始于索引0,其内存地址是1010。
(2) 索引3就在索引0的3个格子之后。
(3) 因为1010 + 3等于1013,所以可以合理推测索引3就在内存地址1013。
一旦计算机知道索引3位于内存地址1013,就能直接跳转过去,读取其中的值"dates"
。
因为计算机读取任意索引只需要跳转到其内存地址这一步,所以数组读取是一个高效的操作。尽管我把计算机的思维过程分为3步,但是我们目前只关注跳转到内存地址这一主要步骤。(后续章节会探究如何确定值得关注的步骤。)
只需要1步的操作自然是最快的操作。作为基本数据结构之一,数组正是因为其高效的读取而大显神通。
假如不是询问计算机索引3的值,而是反过来问"dates"
的索引呢?这就是接下来要讲的查找操作了。