文章目录
一、顺序表的基本结构
1、顺序表的基本布局
存储一组相同类型的数据,为了方便快速取得,将他们按照顺序存放在一起。
数组是实际编程中顺序表的具体体现
比如:存储了1,2,3,元素的一个顺序表
在内存中存储时,1的索引为0,假如物理地址为0x23;
因为1为整数,则存储单元为4个字节,32位,因此
2的索引为1,物理地址为0x23+4=0x27;
同理;
3的索引为2,物理地址为0x27+4=0x31
顺序表的基本结构:
逻辑地址(索引) | 元素存储 | 物理地址 |
---|---|---|
0 | e0 | L0 |
1 | e1 | L0+1xc |
2 | e2 | L0+2xc |
3 | e3 | L0+3xc |
…… | …… | …… |
n-1 | e(n-1) | L0+(n-1)xc |
c:表示不同数据类型对应的存储单元
2、元素外置的顺序表
存储一组不同类型的数据时,为了方便快速取得,将他们的地址按照顺序表的基本结构存放在一起,需要取某个数据时,根据索引,得到数据的物理地址存放的地址,根据这个地址找到数据存放的的物理地址,将物理地址所在位置指向数据
逻辑地址 | 物理地址存放的地址 | 物理地址 | 指向 | 数据 |
---|---|---|---|---|
0 | L0 | 0x23 | -> | e0 |
1 | L0+1xc | 0x55 | ->e1 | |
2 | L0+2xc | 0x809 | -> | e2 |
…… | …… | …… | …… | …… |
n-1 | L0+(n-1)xc | xxx | -> | e(n-1) |
二、顺序表的结构
1、顺序表的结构
容量 | 8 | 表示当前顺序表一共可以容纳多少元素 |
---|---|---|
元素个数 | 4 | 表示当前顺序表目前有的元素个数 |
0 | 3278 | 表示第0个索引存储的数据是 |
1 | 65 | |
2 | 44 | |
3 | 987 | |
4 | ||
5 | ||
6 | ||
7 |
一个顺序表的完整信息包括两部分:
- 表头信息:包括元素存储区的容量和当前表中已有的元素个数
- 数据区:表中的元素的集合
2、顺序表的两种基本实现方式
1)一体式结构
将表头和数据区放在一起的结构
max | num | 元素存储区 |
---|---|---|
8 | 4 |
2)分离式结构
表头部分和元素存储区分开的结构;
其中表头部分除了包括元素存储区的容量和当前表中一存储的元素个数外,还有元素存储区的地址信息
max | num | 元素存储区的地址 |
---|---|---|
8 | 4 | 地址 |
地址指向数据存储的地方
3)两种结构的对比
i、元素存储区的替换
- 分离式结构若想更换数据区,只需将元素存储区的地址指向新的数据存储的地方,即只更换表头信息区的数据区链接地址
- 一体式结构由于表头信息区和数据区连续存储在一起,若想更换数据区,必须将表头和数据区都一起更换,即整体搬迁,将整个顺序表对象改变
ii 、元素存储区扩充:
采用分离式结构的顺序表在扩充存储区时,可以不改变表对象的前提下对数据存储区进行扩张,即所有使用这个表的地方都不必修改,因此不会影响用户对表的使用;
因为其容量可以在使用中动态变化,把使用这种技术的顺序表称为动态顺序表
扩充的两种策略:
- 每次扩充增加固定数目的存储位置, 如每次扩充增加10个元素位置。这种策略称为线性增长
- 特点:节省空间,但是扩充操作频繁,操作次数多
- 每次扩充容量加倍,如每次扩充增加一倍存储空间
- 特点:减少了扩充操作的执行次数,以空间换时间,但可能会浪费空间资源。
3、顺序表的操作
1)例子
i、给顺序表插入111这个元素
a、尾端加入元素,不需要移动其他元素,直接插入,因此时间复杂度为O(1)
b、非保序的加入元素,即将111放在索引1的位置,将索引1原来的元素693移动到尾端,算法步骤为2,所以时间复杂度为O(1)(由于不保序,很少使用)
c、保序的元素插入,将111插入到索引1的位置,其他元素按照原来顺序,都向后移动一位,最坏算法步骤为n,所以时间复杂度为O(n)
ii、删除元素
a、删除表尾元素,时间复杂度为O(1)
b、非保序的元素删除(不常见),比如删除111,删除后,将表尾元素154放到原来111的位置,因此时间复杂度为O(1)
c、保序的元素删除,通插入元素一样,删除后,需要将后面的元素,按顺序全部向前移动一位,因此时间复杂度为O(n)
三、python中的顺序表
python中的列表和元组两种类型的数据采用了顺序表的实现技术(元组是不可变类型,即不变的顺序表)
1、列表基本的实现技术
列表是一种元素个数可变的线性表,可以加入和删除元素,并在各种操作中维持已有元素的顺序(即保序),具有以下行为特征:
- 基于下标(位置)的高效元素访问和更新,时间复杂度为O(1)
- 为满足该特征,采用顺序表技术,表中元素保存在一块连续的存储区中
- 允许任意加入元素,在不断加入元素的过程中,表对象的标识(函数id得到的值)不变
- 为满足该特征,必须能更换元素存储区,并且为保证更换存储区时列表对象的标识id不变,只能采用分离式实现技术
python的官方实现中,列表是一种采用分离式技术实现的动态顺序表(所以list.append(i)比在指定位置插入元素效率高)
python的官方实现中,列表实现采用了如下的策略:
- 在建立空表(或很小的表)时,系统先分配一块能容纳8个元素的存储区
- 执行插入操作(append或insert)时,如果元素存储区满,就换一块4倍大的存储区
- 如果此时的表已经很大(目前的阈值为50000),则改变策略,采用加1倍的方法
- 这样是为了避免出现过多空闲的存储位置