|
|
|
|
移动端

大话数据结构之线性表顺序存储结构

数组的长度是存放线性表的储存空间的长度,存储分配后这个量一般是不变的。 线性表的长度是线性表黄总数据元素的个数,随着线性表插入和删除操作的进行,这个量是变化的。

作者:阿浩来源:大学IT圈|2018-06-06 08:54

技术沙龙 | 邀您于8月25日与国美/AWS/转转三位专家共同探讨小程序电商实战

首先来看「线性表」定义:

线性表(List):零个或多个数据元素的有序排列。

关于线性表的基本操作:

  • Data:线性表的数据对象集合为{a1, a2, ……, an},每个元素的 类型均为 DataType 。其中,除第一个元素 a1 外,每一个元素有且只有一个直接前驱元素,除了 最后一个元素 an 外,每一个元素都有且只有一个直接后继元素。数据元素之间的关系是一一对应的。
  • InitList( *L ):初始化操作,建立一个空的线性表 L 。
  • ListEmpty( L ):若线性表为空,返回 true ,否则返回 false 。
  • ClearList ( *L ):将线性表清空。
  • GetElem( L, i, *e ):将线性表 L 中第 i 个位置的元素值返回给 e 。
  • LocateElem( L, e ):在线性表 L 中查找与给定值 e 相等的元素,如果查找成功,返回该元素在表中序号表示成功;否则,返回 0 表示失败。
  • ListInsert( *L, i, e ):在线性表 L 中的第 i 个位置插入新元素 e 。
  • ListDelete( *L, i, *e):删除线性表 L 中第 i 个位置元素,并用 e 返回其值。
  • ListLength( L ):返回线性表 L 的元素个数。

关于线性表集合 A(La) 和 B(Lb) 的并集操作:

  1. /* 将所有的在线性表 Lb 中但不在 La 中的数据元素插入到 La 中 */ 
  2. void union( List *La, List Lb ){ 
  3.    int La_len, Lb_len, i; 
  4.    ElemType e;     /* 声明与 La 和 Lb 相同的数据元素 e */ 
  5.    La_len = ListLength( La ); 
  6.    Lb_len = ListLength( Lb );     
  7.    for( i = 0 ; i <= Lb_len ; i++ ){ 
  8.        GetElem( Lb, i, e);     /* 取 Lb 中第 i 个数据元素赋给 e */ 
  9.        if( !LocateElem( La, e, equal))      /* La 中不存在和 e 相同数据元素 */ 
  10.            ListInsert( La, ++La_len, e);     /* 插入 */ 
  11.    } 

顺序储存方式

顺序储存方式是在一定的内存空间中,把相同的数据类型的数据依次存放在这块内存空间中。

线性表顺序储存的结构代码:

  1. #define MAXSEZE 20      /* 存储空间初始分配量 */ 
  2. typedef int ElemType;       /* ElemType 类型根据实际情况而定,这里假设为 int */ 
  3. typedef struct{ 
  4.    ElemType data[MAXSIZE];     /* 数组存储数据元素,最大值为 MAXSEZE */ 
  5.    int length;     /* 线性表当前长度 */ 
  6. }SqList; 

在这里我们发现描述顺序储存结构需要三个属性:

  • 存储空间的起始位置:数组 data,它的存数位置就是存储空间的存储位置。
  • 线性表的最大储存容量:数组长度 MAXSIZE。
  • 线性表的当前长度:length。

数组长度与线性表长度区别:

数组的长度是存放线性表的储存空间的长度,存储分配后这个量一般是不变的。 线性表的长度是线性表黄总数据元素的个数,随着线性表插入和删除操作的进行,这个量是变化的。

地址计算方法:

假设每个数据元素占 c 个存储单元(LOC 表示获取存储位置的函数。

  1. LOC( a(i+1) ) = LOC( ai ) + c; 

所以对于第 i 个数据元素 ai 的地址可以由 a1 推算得出:

  1. LOC( ai ) = LOC( a1 ) + (i-1) * c 

顺序存储结构的插入与删除操作

插入操作:

算法思路:

  1. 如果插入位置不合理,抛出异常;
  2. 如果线性表长度大于等于数组长度,则抛出异常或动态增加容量;
  3. 从最后一个元素开始向前遍历到第 i 个位置,分别将他们都像后移动一个位置;
  4. 将要插入元素填入位置 i 处;
  5. 表长增加 1 。
  1. #define OK 1 
  2. #define ERROR 0 
  3. #define TRUE 1 
  4. #define FALSE 0 
  5. typedef int Status; 
  6. /* Status 是函数的类型,其值是函数结果状态码,如 OK 等 */ 
  7. /* 初始条件:顺序线性表 L 已存在,1 <= i <= ListLength( L ) */ 
  8. /* 操作结果:在 L 中第 i 个位置之前插入新的数据元素 e,L 的长度加 1  */ 
  9. Status ListInsert(SqList *L, int i, ElemType e){ 
  10.    int k; 
  11.    if(L.length == MAXSEZE) 
  12.        return ERROR; 
  13.    if(i < 1 || i > L.length + 1) 
  14.        return ERROR; 
  15.    if(i <= L.length){ 
  16.        for(k = L.length - 1; k > i - 1; k--){ 
  17.            L.data[k+1] = L.data[k]; 
  18.        } 
  19.    } 
  20.    L.data[i-1] = e;    /* 将新元素插入 */ 
  21.    L.length++; 

删除操作:

算法思路:

  1. 如果删除位置不合理,抛出异常;
  2. 取出删除元素;
  3. 从删除元素位置开始遍历到最后一个元素位置,分别将他们向前移动一个位置;
  4. 表长减 1 。
  1. /* `` */ 
  2. /* 操作结果:删除 L 的第 i 个元素,并用 e 返回其值,L 的长度减 1 */ 
  3. Status ListDelete (SqList *L, int i, ElemType *e){ 
  4.    int k; 
  5.    if(L.length == 0)   /* 线性表为空 */ 
  6.        return ERROR; 
  7.    if(i < 1 || i > L.length) 
  8.        return ERROR; 
  9.    *e = L.data[i-1]; 
  10.    if(i < L.length){ 
  11.        for( k = i ; k < L.length ; k++){ 
  12.            L.data[k-1] = l.data[k]; 
  13.        } 
  14.    } 
  15.    L.length--; 
  16.    return OK; 

时间复杂度:

根据上次学习,可以推导出 线性表的顺序储存结构在存,读数据时,不管哪个位置时间复杂度都是 O(1);而插入删除时时间复杂度都是 O(n)。这就说明,它比较适合元素个数不太变化,而更多的是存取数据的应用。当然,它的优缺点还不仅这些...

线性表顺序存储结构的优缺点:

优点:

  • 无须为表示表中元素之间的逻辑关系而增加额外的存储空间
  • 可以快速的存取表中任一位置的元素

缺点:

  • 插入和删除操作需要移动大量元素
  • 当线性表长度变化较大时,难以确定储存空间的容量
  • 造成存储空间的“碎片”

【编辑推荐】

  1. 确保数据的质量将优化算法的性能的6个技巧
  2. Linux 下的两种分层存储方案
  3. 存储管理人员需要保持的技能
  4. 从内部部署到云存储的演变
  5. 开源存储,你不知道的六大优势
【责任编辑:武晓燕 TEL:(010)68476606】


点赞 0
分享:
大家都在看
猜你喜欢
24H热文
一周话题
本月最赞

热门职位+更多

读 书 +更多

黑客入侵的主动防御

本书是一本非常全面地讲述黑客入侵主动防御技术的网络安全工具书。本书的重点是介绍黑客的攻击手段和提供相应的主动防御保护措施,在组织结...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊