数据结构中的数组元素的读取之总结

编程基本上就是在跟数据打交道。计算机程序总是在接收数据、操作数据或返回数据。

不管是求两数之和的小程序,还是管理公司的企业级软件,都运行在数据之上。

数据是一个广义的术语,可以指代各种类型的信息,包括最基本的数字和字符串。

在经典的“Hello World!”这个简单程序中,字符串"Hello World!"就是一条数据。

数据都可以将其拆成一堆数字和字符串来看待。

数据结构则是指数据的组织形式。
x = "Hello!"
y = "How are you"
z = "today?"
print x + y + z
程序把3 条数据串成了一句连贯的话。如果要描述该程序中的数据结构,有3 个独立的变量,分别引用着3个独立的字符串。

数据结构不只是用于组织数据,它还极大地影响着代码的运行速度。因为数据结构不同,程序的运行速度可能相差多个数量级。

如果写的程序要处理大量的数据,或者要让数千人同时使用,那么采用何种数据结构,将决定它是能够运行,还是会因为不堪重负而崩溃。

一旦对各种数据结构有了深刻的理解,并明白它们对程序性能方面的影响,就能写出快速而优雅的代码,从而使软件运行得快速且流畅。编程技能也会更上一层楼。

数组

一个允许用户创建和使用购物清单的食杂店应用软件,其源代码可能会包含以下的片段。
array = ["apples", "bananas", "cucumbers", "dates", "elderberries"]
一个数组包含5 个字符串,每个代表从超市买的食物。
用一些名为索引的数字来标识每项数据在数组中的位置。
在大多数的编程语言中,索引是从0 算起的,因此在这个例子中,"apples"的索引为0,"elderberries"的索引为4。

若想了解某个数组的性能,得分析程序怎样操作这一数据结构。
一般数据结构都有以下4 种操作(或者说用法)。
 读取:查看数据结构中某一位置上的数据。对于数组来说,这意味着查看某个索引所指的数据值。例如,查看索引2 上有什么食品,就是一种读取。
 查找:从数据结构中找出某个数据值的所在。对于数组来说,这意味着检查其是否包含某个值,如果包含,那么还得给出其索引。例如,检查"dates"是否存在于食品清单之中,给出其对应的索引,就是一种查找。
 插入:给数据结构增加一个数据值。对于数组来说,这意味着多加一个格子并填入一个值。例如,往购物清单中多加一项"figs",就是一种插入。
 删除:从数据结构中移走一个数据值。对于数组来说,这意味着把数组中的某个数据项移走。例如,把购物清单中的"bananas"移走,就是一种删除。

操作的速度,并不按时间计算,而是按步数计算。
为什么呢?
因为,你不可能很绝对地说,某项操作要花5 秒。它在某台机器上要跑5 秒,但换到一台旧一点的机器,可能就要多于5 秒,而换到一台未来的超级计算机,运行时间又将显著缩短。所以,受硬件影响的计时方法,非常不可靠。
然而,若按步数来算,则确切得多。

如果A 操作要5 步,B 操作要500 步,那么我们可以很肯定地说,无论是在什么样的硬件上对比,A 都快过B。因此,衡量步数是分析速度的关键。

此外,操作的速度,也常被称为时间复杂度

提到速度、时间复杂度、效率、性能,但它们其实指的都是步数。

读取

首先看看读取,即查看数组中某个索引所指的数据值。
这只要一步就够了,因为计算机本身就有跳到任一索引位置的能力。在["apples","bananas", "cucumbers", "dates", "elderberries"]的例子中,如果要查看索引2 的值,
那么计算机就会直接跳到索引2,并告诉你那里有"cucumbers"。
计算机为什么能一步到位呢?

计算机的内存可以被看成一堆格子,其中有些格子有数据,有些则是空白。

当程序声明一个数组时,它会先划分出一些连续的空格子以备使用。换句话说,如果你想创建一个包含5 个元素的数组,计算机就会找出5 个排成一行的空格子,将其当成数组。

内存中的每个格子都有各自的地址,就像街道地址,例如大街123 号。不过内存地址就只用一个普通的数字来表示。而且,每个格子的内存地址都比前一个大1。

计算机之所以在读取数组中某个索引所指的值时,能直接跳到那个位置上,是因为它具备以下条件。

(1) 计算机可以一步就跳到任意一个内存地址上。(就好比,要是你知道大街123 号在哪儿,那么就可以直奔过去。)
(2) 数组本身会记有第一个格子的内存地址,因此,计算机知道这个数组的开头在哪里。
(3) 数组的索引从0 算起。


当我们叫计算机读取索引3 的值时,它会做以下演算。
(1) 该数组的索引从0 算起,其开头的内存地址为1010。
(2) 索引3 在索引0 后的第3 个格子上。
(3) 于是索引3 的内存地址为1013,因为1010 + 3 = 1013。
当计算机一步跳到1013 时,我们就能获取到"dates"这个值了。
所以,数组的读取是一种非常高效的操作,因为它只要一步就好。一步自然也是最快的速度。这种一步读取任意索引的能力,也是数组好用的原因之一。
如果我们问的不是“索引3 有什么值”,而是“"dates"在不在数组里”,那么这就需要进行查找操作了。

 

posted @ 2020-03-29 21:31  jinlanu2  阅读(835)  评论(0编辑  收藏  举报