删除算法的思路:
- 如果删除位置不合理,抛出异常;
- 取出删除元素;
- 从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置;
- 表长减1。
实现代码如下:
/* 初始条件:顺序线性表L已存在,1 ≤ i ≤ ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(SqList *L, int i, ElemType *e)
{
/* 线性表为空 */
if (L->length == 0)
return ERROR;
/* 删除位置不正确 */
if (i < 1 || i > L->length)
return ERROR;
//用e接收返回其删除值
*e = L->data[i - 1];
/* 如果删除不是最后位置 *///包含头删和中删,因为尾删的逻辑和他们不一样
int k;
if (i < L->length)
{
/* 将删除位置后继元素前移 */
for (k = i; k < L->length; k++)
L->data[k - 1] = L->data[k];
}
L->length--;
return OK;
}
//尾删//不需要将将删除位置后继元素前移
void SeqListPopBack(SL* ps)
{
assert(ps);
//ps->a[ps->size - 1] = 0;//没什么意义,万一这个位置本来就是0呢?
ps->size--;
}
现在我们来分析一下,插入和删除的时间复杂度。
- 先来看最好的情况,尾插尾删,如果元素要插入到最后一个位置,或者删除最后一个元素,此时时间复杂度为O(1),因为不需要移动元素的。
- 最坏的情况呢,头插头删,如果元素要插入到第一个位置或者删除第一个元素,此时时间复杂度是多少呢?那就意味着要移动所有的元素向后或者向前,所以这个时间复杂度为O(n)。
至于平均的情况,中插中删,由于元素插入到第i个位置,或删除第i个元素,需要移动n-i个元素。根据概率原理,每个位置插入或删除元素的可能性是相同的,也就说位置靠前,移动元素多,位置靠后,移动元素少。最终平均移动次数和最中间的那个元素的移动次数相等,为(n-1)/2。
我们前面讨论过时间复杂度的推导,可以得出,平均时间复杂度还是O(n)。
这说明什么?
线性表的顺序存储结构,在存、读数据时,不管是哪个位置,时间复杂度都是O(1);而插入或删除时,时间复杂度都是O(n)。
这就说明,它比较适合元素个数不太变化,而更多是存取数据的应用。当然,它的优缺点还不只这些……