基本实现方式
最常见的情况为一个表中保存的元素类型相同,因此每个元素所需存储量相同,首元素放置在存储区的起始位置,其余元素一次放置,逻辑顺序关系通过元素的位置关系表明。存取操作时间可在
O(1)
时间内完成。
假设起始位置的内存地址为
l0
,表元素编号从0开始,则元素
e0
存储在内存位置为
Loc(e0)=l0
的位置,再假定一个元素所需单元存储数为
c=size(元素)
,则元素
ei
的地址计算公式为:
Loc(ei)=Loc(e0)+c∗i
这种情况下的 size(元素) 为静态确定的,如果表中元素大小不同,可以在每个 size(元素) 中存储元素的链接,改链接指向列表中的元素。
因为表可以加入删除数据,所以在构建表的时候应该分配一块足以容纳当前元素个数的内存,还要保留一些空位,以满足增加元素的需要。把已有的元素放在前面,空位留在后边;同时记录存储区的大小和元素个数,在以后的变动操作时,每次都要更新元素个数。
顺序表的基本操作
假设用 max 表示表的容量, num 表示当前元素个数。
创建和访问操作:
- 创建空表:
分配适当的内存,记录表的容量和元素个数( max 和 num )。 - 简单判断操作:
判断表空: num=0 ;判断表满: num=max ;这两个操作时间复杂度都为 O(1) 。 - 访问给定下标
i
的元素:
首先检查i 的值是否在有效范围内: 0≤i≤num−1 ,然后根据上面公式算出元素的地址,得到元素对象,操作时间复杂度为 O(1) 。 - 遍历操作:
用一个整数在记录遍历达到的位置,访问前一元素减一,访问后一元素加一,根据上方的公式可以在 O(1) 时间内访问元素,遍历中要保证整数在合法范围内。 - 查找给定元素
d
的位置:
基于元素的下标,从0 开始至表中元素个数时结束,每次用 d 与当前下标元素比较,相同时返回元素下标,找不到时返回一个特殊值(−1 ),完成的时间与元素的个数有关,所以时间复杂度为 O(n) 。 按特定条件查找元素 d :
同上,每次取出一个元素检查是否符合条件。
变动操作:加入元素
- 尾端加入
检查是否有空位,然后把新元素加入到第一个空位,并跟新计数num ,时间复杂度为 O(1) 。 - 在位置
i
处插入新元素
首先检查i 是否合法,表是否未满,然后有两种情况:
- 不保留原来元素的顺序
把原来 i 的元素放在表的最后,然后把新元素插入到i 的位置,更新计数 num ,时间复杂度为 O(1) 。 - 保留原来元素顺序
这种情况就需要把 i 位置之后的元素逐一后移一位,再把新元素插入到i 的位置,更新计数 num ,时间复杂度为 O(n) 。
- 不保留原来元素的顺序
变动操作:删除元素
- 尾端删除
直接将元素计数值 num−1 。 - 删除位置
i
处的元素
首先检查i 是否合法,这也有两种情况:
- 不保留原来元素顺序
把最后一个元素移到位置 i ,覆盖原来的元素,更新计数num ,时间复杂度为 O(1) 。 - 保留原来元素顺序
删除位置 i 处的元素后,将之后的元素逐一前移一位,更新计数num ,时间复杂度为 O(n) 。
- 不保留原来元素顺序
顺序表的结构
一个顺序表的完成信息包含两部分:表中元素的集合和为实现正确操作所需的信息。所以这两部分信息结合也有两种情况。
一体式结构整体性强,易于管理,但是随着表中元素数量的增加,表的容量增大时会受到限制。
分离式结构虽然复杂一些,但是后期可以更换储存区的大小,表还是原来的表,内容可以不变,但是容量增加了。
更换存储区过程:
1. 另外申请一块更大的储存区。
2. 把表中已有元素复制到新储存区。
3. 改变表对象的元素区链接,指向新的储存区,更改表的信息。
4. 后续加入元素操作。