删除算法的思路:

    • 如果删除位置不合理,抛出异常;
    • 取出删除元素;
    • 从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置;
    • 表长减1。

    实现代码如下:

    1. /* 初始条件:顺序线性表L已存在,1 ≤ i ≤ ListLength(L) */
    2. /* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
    3. Status ListDelete(SqList *L, int i, ElemType *e)
    4. {
    5. /* 线性表为空 */
    6. if (L->length == 0)
    7. return ERROR;
    8. /* 删除位置不正确 */
    9. if (i < 1 || i > L->length)
    10. return ERROR;
    11. //用e接收返回其删除值
    12. *e = L->data[i - 1];
    13. /* 如果删除不是最后位置 *///包含头删和中删,因为尾删的逻辑和他们不一样
    14. int k;
    15. if (i < L->length)
    16. {
    17. /* 将删除位置后继元素前移 */
    18. for (k = i; k < L->length; k++)
    19. L->data[k - 1] = L->data[k];
    20. }
    21. L->length--;
    22. return OK;
    23. }
    24. //尾删//不需要将将删除位置后继元素前移
    25. void SeqListPopBack(SL* ps)
    26. {
    27. assert(ps);
    28. //ps->a[ps->size - 1] = 0;//没什么意义,万一这个位置本来就是0呢?
    29. ps->size--;
    30. }

    现在我们来分析一下,插入和删除的时间复杂度。

    • 先来看最好的情况,尾插尾删,如果元素要插入到最后一个位置,或者删除最后一个元素,此时时间复杂度为O(1),因为不需要移动元素的。
    • 最坏的情况呢,头插头删,如果元素要插入到第一个位置或者删除第一个元素,此时时间复杂度是多少呢?那就意味着要移动所有的元素向后或者向前,所以这个时间复杂度为O(n)

    至于平均的情况,中插中删,由于元素插入到第i个位置,或删除第i个元素,需要移动n-i个元素。根据概率原理,每个位置插入或删除元素的可能性是相同的,也就说位置靠前,移动元素多,位置靠后,移动元素少。最终平均移动次数和最中间的那个元素的移动次数相等,为(n-1)/2

    我们前面讨论过时间复杂度的推导,可以得出,平均时间复杂度还是O(n)。
    这说明什么?
    线性表的顺序存储结构,在存、读数据时,不管是哪个位置,时间复杂度都是O(1);而插入或删除时,时间复杂度都是O(n)。

    这就说明,它比较适合元素个数不太变化,而更多是存取数据的应用。当然,它的优缺点还不只这些……