zfk_蓝桥杯C++学习_语言基础_线性表及顺序表

一、线性表

1.定义: 由n(n≥0)个数据特性相同的元素构成的有限序列,称为线性表。

2.线性表的特点:
线性表是n个数据元素的有限序列,其中n个数据是相同数据类型的。

线性表中元素的个数n(n≥0)定义为线性表的长度,当n=0时称之为空表。

对于非空的线性表或线性结构,其特点是:
(1)存在唯一的一个被称作“第一个”的数据元素;
(2)存在唯一的一个被称作“最后一个”的数据元素;
(3)除第一个元素外,结构中的每个数据元素均只有一个前驱;
(4)除最后一个元素外,结构中的每个数据元素均只有一个后继。

3.线性表 ADT

ADT List 
{
    数据对象:D={ailai∈ ElemSet,i=1,2, ... ,n,n≥0}

    数据关系:S={<ai-1,ai>|ai-1,ai ∈ D, i=2, ... ,n}

    基本操作:
        InitList (&L)
        操作结果:构造一个空的线性表L。
        DestroyList (&L)
        初始条件:线性表L已存在。
        操作结果:销毁线性表L。
} ADT List

二、顺序表

1.定义: 用一组连续的内存单元依次存储线性表的各个元素,也就是说,逻辑上相邻的元素,实际的物理存储空间也是连续的。

2.基本操作:

(1)顺序表-初始化

#define MAXSIZE 100
typedef int ElemType;

typedef struct
{
    ElemType data [MAXSIZE];
    int length;
} SeqList;

void initList (SeqList *L)
{
    L->length = 0;
}

(2)顺序表-在尾部添加元素

int appendElem(SeqList *L, ElemType e)
{
    if (L->length>=MAXSIZE)
    {
        printf("顺序表已满\n");
        return 0;
    }
    L->data[L->length] = e;
    L->length++;
    return 1;
}

(3)顺序表-插入元素

int insertElem(SeqList *L, int pos, ElemType e)
{
    if (pos <= L->length)
    {
        for (int i = L->length-1; i >= pos-1; i -- )
        {
            L->data[i+1] = L->data[i];
        }
        L->data[pos-1] = e;
        L->length++;
    }
    return 1;
}

(4)顺序表-删除元素

int deleteElem(SeqList *L, int pos, ElemType *e)
{
    *e = L->data [pos-1] ;
    if (pos < L->length)
    {
        for (int i = pos; i < L->length; i++)
        {
            L->data[i-1] = L->data[i];
        }
    }

    L->length --;
    return 1;
}

(5)顺序表-遍历

void listElem (SeqList *L)
{
    for (int i = 0; i < L->length; i++)
    {
        printf("%d ", L->data[i]) ;
    }
    printf("\n");
}

(6)顺序表-查找

int findElem(SeqList *L, ElemType e)
{
    for (int i = 0; i < L->length; i++)
    {
        if (L->data[i] == e)
        {
            return i + 1;
        }
    }
    return 0;
}

(7)顺序表-动态分配内存地址初始化

typedef struct
{
    ElemType *data;
    int length;
} SeqList;

SeqList* initList ()
{
    SeqList *L = (SeqList*)malloc(sizeof(SeqList));
    L->data = (ElemType*) malloc(sizeof (ElemType)*MAXSIZE);
    L->length = 0;
    return L;
}

3.缺点:
顺序表作为基于连续内存空间的数据结构,不管是静态还是动态实现方式,都存在插入删除效率低、扩容有额外开销等缺点。

(1)插入与删除操作效率低:顺序表要保持元素的连续存储特性,当在表头或表中间位置执行插入操作时,得把目标位置及之后的所有元素依次后移,才能腾出空间;删除这类位置的元素时,又要把删除位置之后的元素依次前移来填补空缺。这些操作都要移动大量元素,时间复杂度为 O (n),数据量越大,操作耗时越明显。例如在有 1000 个元素的顺序表第 10 位插入元素,就需要移动后续 991 个元素。

(2)扩容操作存在额外开销:静态顺序表的大小固定,一旦元素数量达到预设上限就无法继续插入;动态顺序表虽可扩容,但过程繁琐。通常要先申请一块更大的新内存,接着将旧空间中的所有数据复制到新空间,最后释放旧空间。而且若扩容策略不合理,比如每次只扩容 1 个单位,插入 n 个元素可能产生 O (n²) 的时间成本;即便采用翻倍扩容的推荐策略,扩容时的数据拷贝操作依旧会带来短暂的性能损耗。

(3)空间利用率不佳:静态顺序表容易出现空间浪费或不足的问题,预设空间过大,多余部分会闲置;预设过小又会提前达到存储上限,无法新增元素。动态顺序表也有缺陷,扩容后若后续删除了大量元素,多出来的空闲空间往往不能自动释放,只能手动处理(部分编程语言),这就造成了内存的无效占用。比如动态顺序表扩容到 200 个存储单元后,若元素减少到 50 个,剩余 150 个单元的空间就被浪费了。

(4)依赖连续内存空间:顺序表需要一块完整连续的内存区域存储数据。当数据量较大时,系统中可能难以找到适配的连续内存块,即便此时系统整体剩余内存总量足够,也无法满足顺序表的存储需求,从而限制了其存储大规模数据的灵活性。

(5)易引发内存相关问题:在 C/C++ 等需要手动管理内存的语言中,动态顺序表若使用后忘记释放内存,会造成内存泄漏;同时扩容后旧空间若释放不当,还可能产生内存碎片。这些问题不仅浪费系统资源,还可能导致程序运行异常,增加了开发中的内存管理难度。

posted @ 2025-12-17 00:06  一乔  阅读(13)  评论(0)    收藏  举报