顺序表
一、什么是顺序表
将元素顺序的存放在一块连续的存储区中,元素间的顺序关系由它们的存储顺序自然表示。
(一)顺序表的形式
顺序表由于存储的元素类型不同,分成:
- 基本顺序表
- 元素外置顺序表
为什么要这样分呢?因为元素类型不同占用的每个单元大小不同。
1、基本顺序表
数据元素本身连续存储,每个元素所占的存储单元大小固定相同,元素的下标是其逻辑地址,而元素存储的物理地址(实际内存地址)可以通过存储区的起始地址Loc (e0)加上逻辑地址(第i个元素)与存储单元大小(c)的乘积计算而得:
Loc(ei) = Loc(e0) + c*i
比如,列表li=[23,56,100,200]的存储:
一个整数占4个字节,一个字节占32位,所以4Byte=32位,上面4个整数在内存中以顺序表的形式存储,通过存储区的起始位置0x13可以找到后面的任意位置的元素,所以访问指定元素时无需从头遍历,通过计算便可获得对应地址,其时间复杂度为O(1)。
2、元素外置顺序表
针对元素大小不统一,比如li = [15,"abc",56,12.32],里面整型、字符串、浮点型占用的字节不同,但是顺序表是存储的是连续的单位大小相同的元素,此时考虑使用元素外置的顺序表:
- 右边存储的是具体的数据,因为元素种类不同,所以在内存中不一定是连续的
- 左边顺序表中存储的是右边数据的内存地址
- 因为内存地址元素可以申请一块连续的空间来存,并且元素种类、大小一样
这样通过元素链接的存储位置,而后顺着链接找到实际存储的数据元素。
(二)顺序表的结构与实现
1、顺序表的结构
一个完整的顺序表包含两部分内容:
- 元信息(容量和元素个数)
- 元素集合
2、顺序表的两种基本实现方式
顺序表中有两种基本实现方式:一体式结构、分离式结构。
- 一体式结构
存储表信息的单元与元素存储区以连续的方式安排在一块存储区里,两部分数据的整体形成一个完整的顺序表对象。
- 分离式结构
表对象里只保存与整个表有关的信息(即容量和元素个数),实际数据元素存放在另一个独立的元素存储区里,通过链接与基本表对象关联。
一体式结构由于顺序表元信息区与数据区是在一起的,所以如果想更换数据区只能整体搬迁,这样的话整个顺序表对象(指存储顺序表的元信息的区域)就改变了;分离式结构若想更换数据区,只需要将元信息中的数据区的链接地址更新即可,顺序表表对象不用变化。
另外,如果对顺序表中的数据区进行扩充有两种策略:
- 线性增长
每次增加固定数量的存储位置,比如每次增加20个存储位置;该方式节约空间,但是操作频繁
- 倍增
每次在原先容量的基础上进行成本增长,比如:8-->16,16-->32,该方式减少了操作次数,但是可能会浪费空间,以空间换时间。
二、Python中的顺序表
Python中的list和tuple采用的就是顺序表的实现技术,只不过tuple是不可变类型,即是不可变的顺序表。
list是一种采用分离式技术的动态顺序表,list的实现采用了如下的策略:
在建立空表时,系统分配一块容内8个元素的存储区,在执行插入(insert/append)操作,如果存储区满就换一块4倍大的空间;但如果此时的表已经很大,则改变策略,采用加一倍的方法。引入这种改变策略的方式,是为了避免出现过多空闲的存储位置。