5.0、C语言数据结构——线性表 ( 2 )

5.0、C语言数据结构——线性表 ( 2 )

线性表的顺序存储结构:

        1. 我们可以想象,线性表有两种物理存储结构:顺序存储结构和链式存储结构;
        2. 线性表的顺序存储结构,指的是用一段连续的地址存储单元一次存储线性表的数据元素
        3. 线性表 (a1 , a2 , ... , an)的顺序存储如下:

        物理上的存储方式事实上就是在内存中找个初始地址,然后通过站位的形式,把一定的内存空间给占了,然后把相同的数据类型的数据元素依次放在这块空地中

        接下来看线性表顺序存储的结构代码:

#edfine MAXSIZE 20
typedef int ElemType;
typedef struct {
    ElemType data[MAXSIZE];
    int length;
} SqList;

        大家看到了,这类我们封装了一个结构,事实上就是对数组进行封装,增加了当前长度的变量罢了;

总结下,顺序存储结构封装需要三个属性:
        1. 存储空间的起始位置,数组data,它的存储位置就是线性表存储空间的存储位置;
        2. 线性表的最大存储容量:数组的长度MaxSize;
        3. 线性表的当前长度:length;

注意 ->
    
    数组的长度与线性表的当前长度需要区分一下:数组的长度是存放线性表的存储空间的总长度,一般初始化后不变。而线性表的当前长度是线性表中元素的个数,是会变化的;

        假设ElemType 占用的是 c 个存储单元(字节),那么线性表中第 i + 1 个数据元素和第 i 个数据元素的存储位置的关系是(LOC表示获得存储位置的函数) : LOC( ai + 1 ) = LOC( ai ) + c;

        所以对于第 i 个数据元素 ai 的存储位置可以由 a1 推算得出 : LOC ( ai ) = LOC(a1) + ( i - 1 ) * c ;
        结合下图来理解:

         通过这个公式,我们可以随时计算出线性表中任意位置的地址,不管他是第一个还是最后一个,都是相同的时间。那么他的存储时间性能当然就为 0( 1 ) ,我们通常称为随机存储结构;

        实现 GetElem 的具体操作,即将线性表 L 中的第 i 个位置元素返回。就程序而言非常简单了,我们只需要把数组第 i -1 下标的值返回即可;
        实现代码,如下所示: 
 

Status GetElem (SqList L , int i , ElemType* e) {
    if( L.length == 0 || i < 1 || i > L.length ) {
        return ERROR;
    }
    *e = L.data(i - 1);
    return OK;
}

        注意这里返回值类型 Status 是一个整型,约定返回 1 代表 OK , 返回 0 代表 ERROR。今后还会出现,也是使用同样的约定,不再详述;

        刚才我们也谈到,线性表的顺序存储结构具有随机存储结构的特点,时间复杂度为 O ( 1 );
        大家现在来考虑下,如果我们要实现,ListInsert ( *L , i , e ),即在线性表 L 中的第 i 个位置插入新元素 e ,代码应该如何写?

所以插入算法的思路:
        1. 如果插入位置不合理,抛出异常;
        2. 如果线性表长度大于等于数组长度,则抛出异常或动态增阿基数组容量;
        3. 从最后一个元素开始向前遍历到第 i 个位置,分别将他们都向后移动一个位置;
        4. 将要插入元素填入位置 i 处;
        5. 线性表长 + 1

Status ListInsert(SqList* L , int i , ElemType e) {
    int k;
    if(L->length == MAXSIZE) {
        return ERROR;
    }
    if(i < 1 || i > L->length + 1) {
        return ERROR;
    }
    if(i<=L->length) {
        for(k = L->length-1;k >= i-1;k--) {
            L->data[k+1] = L->data[k];
        }
    }
    L->data[i-1] = e;
    L->length++;
    return OK;
}

        1. 现在我们分析一下,插入 和 删除 的时间复杂度;
        2. 最好的情况:插入和删除操作刚好要求在最后一个位置操作,因为不需要移动任何元素,所以此时的时间复杂度O ( 1 );
        3. 最坏的情况:如果要插入和删除的位置是第一个元素,那就意味着要移动所有的元素向后或者向前,所以这个时间复杂度为 O ( n );
        4. 至于平均情况,就去中间值 O( ( n - 1 ) / 2 );
        5. 按照前边游戏秘籍指导,平均情况复杂度简化后还是 O ( n );
        6. 线性表的顺序存储结构,再存、读数据时,不管哪个位置,时间复杂度都是O ( 1 );而在插入或删除时,时间复杂度都是 O ( n );
        7. 这就是说明,他比较合适元素个数比较稳定,不经常插入和删除元素,而个更多的操作时存取数据的应用;

那我们接下来给大家简单总结一下线性表的顺序存储结构的优缺点:

        优点:
                1. 无须为表示表中元素之间的漏记关系而增加额外的存储空间;
                2. 可以快速地存取表中任意位置的元素;
        缺点:
                1. 插入和删除操作需要移动大量元素;
                2. 当线性表长度变化较大时,难以确定存储空间的容量;
                3. 容易造成存储空间的 “ 碎片 ”;

        1. 前面我们讲的线性表的顺序存储结构,他最大的缺点就是插入和删除时需要移动大量元素,这显然就需要耗费时间;
        2. 那我们能不能针对这个缺陷或者说遗憾提出解决的方法呢?要解决这个问题,我们就得考虑一下导致整个问题的原因?
        3. 为什么当插入和删除时,就要移动大量的元素?
        原因就在于相邻两个元素的存储位置也具有邻居关系,他们在内存中的位置是紧挨着的,中间没有间隙,当然就无法快速插入和删除;   
                

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值