数组
一、数组
数组(array)表示的是可以在给定的索引位置访问或替代的项的一个序列。你可能认为,这表述和python列表的表述有点像。实际上,python列表的底层数据结构就是数组。尽管python程序员通常会在你想要使用数组的地方使用列表,但是在python和许多其他的编程语言中,集合中的实现结构主要是数组,而不是列表。因此,需要熟悉数组的方式来思考问题。
程序员可以在未定的位置访问或替代数组的一个项,查看数组的长度,以及获取其字符串表示,但也只能做这么多。程序员不能添加或删除某一位置的项,或者让数组的长度变大变小。通常,数组的长度或容量在创建的时候就固定下来了。
二、随机访问和连续内存
下标或者索引操作,是的程序员很容易就能够储存或访问给定位置的项。数组索引操作也非常快。数组索引是一个随机的访问操作。在随机访问中,计算机通过执行一定数目的步骤,获取第i项的位置。因此不管数组有多大,他访问第一项所需的时间和访问最后一项所需的时间都是相同的。
计算机通过给数组项分配一段连续的内存单元,从而支持随机访问。
机器地址是8位二进制数字。由于地址在编号上是连续的,数组在某一项的地址通过将两个值相加得到,即将数组的基本地址和项的位偏移地址相加。数组的基本地址是数组的第1项的机器地址。一个项的偏移地址等于它的索引乘以数组的一项所需的内存单元项目的一个常量表示(在python中这个值总是1).概括起来,python数组的索引操作有两个步骤:
- 获取数组内存块的基本地址。
- 给这个地址加上索引,返回最终结果。
需要注意的是,随机访问是这样的,计算机不一定必须在数组中搜索第一个给定的单元,否则计算机就必须要从第1个单元开始访问,直到到达第n个单元。常量时间的随机访问,可能是数组最想要的功能。然而,这一功能要求数组必须用一段连续的内存来表示。正如你随后将看到的,当在数组上实现其他操作的时候,这回需要付出一些代价。
三、静态内存和动态内存
在FORTRAN和Pascal这样层级的语言中,数组是静态的数据结构。数组的长度和大小都是在编译时确定好的。因此成需要需要用一个常量来指定这一大小。由于程序员不能够在运行时修改数组的长度,他需要预计程序的所有应用将会需要多少数组的内存。如果程序总是一个已知项数固定的数组,那没有问题。但是很多其他的情况下,数组项的数目是变化的,程序员必须请求足够的内存才能满足数组的项数达到最大项目的情况。显然,这种需求会导致程序对很多应用来说都是浪费了内存。糟糕的是,当项的项数超出数组的长度时,程序员所能做的也是返回一个错误消息而已。
像Java和C++这样的现代语言,通过允许程序员创建动态数组来弥补这一问题。就像静态数组一样,动态数组占据了连续的内存块并支持随机访问。在运行时并不需要知道动态数组的长度。因此,Java和C++程序员可以在实例化的时候指定一个动态数组的长度。python的Array类也有类似的行为。
好在,对程序员来说,有一种可以在运行时根据应用程序的需求来调整数组的长度。这种调整可以采取如下三种形式:
- 在程序开始的时候创建一个具有合理默认大小的数组。
- 当这个数组不能保存更多的数据的时候,创建一个新的、更大的数据,并且从旧的数组转移数据项。
- 当数组似乎在浪费内存的时候(有一些数据已经被应用程序删除了),以一种类似的方式来减少数组的长度。
对于python列表来说,这些调整都是自动进行的。
四、物理大小和逻辑大小
数组的物理大小是它的数组单元的总数,或者说在创建数组的时候,用来指定其容量的数字。数字的逻辑大小,是它当前可提供应用程序使用的项的数目。
结束!