目录
线性表的存储结构分为顺序存储结构和链式存储结构。本文主要展开讲讲线性表的顺序存储结构。
一、线性表的顺序存储表示
1.顺序存储
线性表的顺序存储表示又叫顺序存储结构或顺序映像。
顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。
简而言之,逻辑上相邻,物理上也相邻。
线性表的第一个数据元素a1的存储位置,称作线性表的起始位置或基地址。
2.顺序存储结构
典型的线性表顺序存储结构:依次储存、地址连续——中间没有空出存储单元。
线性表顺序存储结构占用一片连续的存储空间,知道某个元素的存储位置就可以计算出其他元素的存储位置。
3.线性表中元素存储位置的计算
LOC(ai)=LOC(a1)+(i-1)*l
其中a1为基地址,l为每个元素需占的存储单元个数。
顺序表的特点:①以物理位置相邻表示逻辑关系;
②任一元素均可随机存取(优点)
二、顺序表的顺序存储实现
顺序表(元素)有地址连续、依次存放、随机存取、类型相同等特点,与数组(元素)相似,因此可用一维数组表示顺序表。
但线性表长可变(删除),而数组长度不可动态定义,因此还需用一动态变量表示顺序表的长度属性。
逻辑结构直接映射到存储结构时:逻辑位序和物理位序相差1。
补充:操作算法中用到的预定义常量和类型
//函数结果状态代码
#define TURE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef char ElemType;
顺序表基本操作的实现——补充:几个简单操作
线性表L的初始化(参数用引用)
Status InitList_Sq(SqList &L){ //构造一个空的顺序表L
L.elem=new ElemType[MAXSIZE]; //为顺序表分配空间
if(!L.elem)exit(OVERFLOW); //存储分配失败
L.length=0; //空表长度为0
return OK;
销毁线性表L
void DestroyList(SqList &L){
if(L.elem)delete L.ekem; //释放存储空间
}
清空线性表L
void ClearList(SqList &L){
L.length=0; //将线性表的长度置为0
}
求线性表L的长度
int GetLength(SqList L){
return(L.Length);
}
判断线性表是否为空
int IsEmpty(SqList L){
if(L.Length==0)return 1;
else return 0;
}
顺序表的取值(根据位置i获取相应位置数据元素的内容)
int GetElem(SqList L,int i,ElemType &e){
if(i<1||i>L.Length)return ERROE; //判断i值是否合理,若不合理,返回ERROR
e=L.elem[i-1]; //第i-1单元存储着第i个数据
return OK;
}
随机存取
顺序表的查找
- 在线性表L中查找与指定值e相同的数据元素的位置
- 从表的一端开始,逐个进行记录的关键字和给定值的比较。找到,返回该元素的位置序号,未找到,返回0。
int LocateElem(SqList L,ElemType e){
//在线性表L中查找值为e的数据元素,返回其序号(是第几个元素)
for(i=0;i<L.Length;i++)
if(L.elem[i]==e)return i+1; //查找成功,返回序号
return 0; //查找失败,返回0
}
算法分析:
查找算法的基本操作为:将记录的关键字同给定值进行比较
基本操作:L.elem[i]==e
平均查找长度ASL:为确定记录在表中的位置,需要与给定值进行比较的的关键字的个数的期望值叫做查找算法的平均查找长度。
顺序表的插入:
Status ListInsert_Sq(SqList &L,int i,ElemType e){
if(i<1||i>L.length+1)return ERROR; //值不合法
if(L.length==MAXSIZE)return ERROR; //当前存储空间已满
for(j=L.length-1;j>=i-1;j--)
L.elem[j+1]=L.elem[j]; //插入位置及之后的元素后移
L.elem[i-1]=e; //将新元素e放入第i个位置
L.length++ //表长加1
return OK;
}
算法分析:
算法时间主要耗费在移动元素的操作上
- 若插入在尾结点之后,则根本无需移动(特别快);
- 若插入在尾结点之前,则表中元素全部后移(特别慢);
- 若要考虑在各种位置插入(共n+1种可能)的平均移动次数,该如何计算?
顺序表插入算法的平均时间复杂度为O(n).
顺序表的删除
Status ListDelete Sq(SqList &L,int i){
if((i<1)||(i>L.length))return ERROR; //值不合法
for(j=i;j<=L.length-1;j++)
L.elem[j-1]=L.elem[j]; //被删除元素之后的元素前移
L.length--; //表长减一
return OK;
}
算法分析:
算法时间主要耗费在移动元素的操作上
- 若删除尾结点,则根本无需移动(特别快);
- 若删除首结点,则表中n-1个元素全部前移(特别慢);
- 若要考虑在各个位置删除(共n种可能)的平均移动次数,该如何计算?
平均时间复杂度为O(n).
顺序表的操作算法分析
时间复杂度:
查找、插入、删除算法的平均时间复杂度为O(n)
空间复杂度:
显然,顺序表操作算法的空间复杂度S(n)=O(1)
(没有占用辅助空间)
顺序表的优缺点
优点:
- 存储密度大(结点本身所占存储量/结点结构所占存储量)
- 可以随机存取表中任一元素
缺点: 为克服这一缺点,可使用链表
- 在插入、删除某一元素时,需要移动大量元素
- 浪费存储空间
- 属于静态存储形式,数据元素个数不能自由扩充
三、类C语言有关操作补充
C语言的内存动态分配:(需加载头文件<stdlib.h>)
malloc(m)函数:开辟m字节长度的地址空间,并返回这段空间的首地址
sizeof(x)运算:计算变量x的长度
free(p)函数:释放指针p所指变量的存储空间,即彻底删除一个变量