前言
在学习了 第一章 - 初识数据和结构 、第二章 - 初识算法 之后,今天我们来学习一下线性表!
一、线性表是什么?
是零个或多个数据元素的 有限序列
- 序列:元素之间是有顺序的,若元素存在多个,则第一个元素无前驱,最后一个元素无后继,其他每个元素都有且只有 个前驱和后继
- 有限:在计算机中处理的对象都是有限的
若将线性表记为 ( a1 ,…, ai-1 , ai , ai+1 ,…, an ),则称 ai-1 为 ai 的直接前驱元素、ai+1为 ai 的直接后继元素。
提问:班级花名册是线性表吗?
学号 | 姓名 | 性别 | 出生年月 | 住址 |
---|---|---|---|---|
1 | 刘强东不知妻美 | 男 | 1973.03 | DGUT莞博社区23栋219室 |
2 | 古天乐平平无奇 | 男 | 1970.10 | DGUT莞华社区14栋205室 |
3 | 撒贝宁北大还行 | 男 | 1976.03 | DGUT莞逸社区21栋509室 |
… | … | … | … | … |
是的,别忘了数据元素可以由若干个数据项组成。
二、线性表的顺序存储结构
线性表的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素
顺序存储示意图如下:
顺序存储方式:寻找一片连续的地址,把相同数据类型的数据元素依次存放
可以用C语言(其它语言也相同)的一维数组来实现顺序存储结构即把第一个数据元素存到数组下标为0的位置中,接着把线性表相邻的元素存储在数组中相邻的位置
1.顺序存储结构的创建
// 线性表的顺序存储的结构代码
#define MAXSIZE 20 //存储空间初始分配量
typedef int ElemType; //设定ElemType为int型,可根据需求设置成其他类型
typedef struct{
ElemType data[MAXSIZE]; //创建最大值为MAXSIZE的ElemType型数组data
int length; //线性表当前长度
}SqList;
顺序存储结构的三个属性:
- 数组data的存储位置就是存储空间的存储位置
- 线性表的最大存储容量:数组长度 MAXSIZE
- 线性表当前长度:length
区分好数组长度和线性表长度:
- 数组的长度:是存放线性表的存储空间的长度
- 线性表的长度:是线性表中数据元素的个数,随着线性表插入和删除操作的进行,这个量是变化的。
地址计算方法:线性表的第 i 个元素是要存储在数组下标为 i - 1 的位置(C语言)
假设每个数据元素占用 c 个存储单元 LOC 表示获得存储位置的函数
LOC(ai+1)=LOC(ai)+c
所以对于第i个数据元素ai的存储位置可以由a1推算出:
LOC(ai)=LOC(a1)+(i - 1)*c
通过LOC公式,易得顺序存储结构得存取时间复杂度为O(1),通常把对每个位置存取对于计算机都是相同时间的存储结构称为随机存取结构。
2.顺序存储结构的查询、插入和删除
// 声明一下自定义变量
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int Status; // 是函数的类型,值为函数结果状态代码,如ok
// 初始条件:顺序线性表 L 已存在,1 < = i < = ListLength(L)
查询算法
// 操作结果:用 e 返回 L 中第 i 个数据元素的值
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;
}
插入算法
思路;
- 如果插入位置不合理,抛出异常;
- 如果线性表长度大于等于数组长度,则抛出异常或动态增加容量;
- 从最后一个元素开始向前遍历到第 i 个位置,分别将它们都向后移动一个位置;
- 将要插入元素填入位置 i 处;
- 表长加1
代码实现:
// 操作结果:在 L 中第 i 个位置之前插入新的数据元素e,L的长度加1
Status ListInsert(SqList *L,int i,ElemType e){
int k;
if(L->length==MAXSIZE) //顺序表满了
return ERROR;
if(i<1 || i>L->length+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; //插入新元素e
L->length++;
return OK;
}
删除算法
思路
- 如果删除位置不合理,抛出异常
- 取出删除元素;
- 从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置;
- 表长减1
代码实现:
// 操作结果:删除 L 的第 i 个元素,并用e返回其值,L的长度减1
Status ListDelete(SqList *L,int i,ElemType *e){
int k;
if(L->length==0) //线性表为空
return ERROR;
if(i<1 || i>L->length) //删除位置i不在范围内,这里L->length是指删去最后一个元素
return ERROR;
*e=L->data[i-1]; //取出数据元素
if(i<L->length){ //删除位置不在表尾,等效i<=L->length-1,L->length-1为最后一个数据元素的位置
for(k=i;k<L->length;k++)
L->data[k-1]=L->data[k]; //数据元素前移
}
L->length--;
return OK;
}
3.顺序存储结构的优缺点
优点 | 缺点 |
---|---|
无须为表示表中元素之间的逻辑关系而增加额外的存储空间 | 插入和删除操作需要移动大量元素 |
可以快速地存取表中任一位置的元素 | 当线性表长度变化较大时,难以确定存储空间的容量 |
造成存储空间的”碎片“ | |
查询时间复杂度为O(1) | 删除和插入的时间复杂度都是O(n) |
最后有话讲
以上内容为 大话数据结构 – 程杰 第三章关于顺序存储的学习笔记。
虽然和成为Java工程师有一段距离,但是没关系,我是一个一旦确立目标就很有干劲的人,一定能成功!
如果有跟我一起学习的同学可以帮我指正那就更好了,欢迎加入我的交流群 916352394。