1. 顺序表的定义
1.1 什么是顺序表?
顺序表是用一组地址连续的存储单元依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。
注意:顺序表是线性表的存储结构,顺序表描述的是存储上相邻,线性表是逻辑结构,线性表描述的是逻辑上相邻。
1.2 顺序存储
什么是地址连续?
什么是存储单元?
线性表中的数据元素占用的存储单元是多大?
每个数据元素占用的存储单元大小相同吗?
什么是地址连续?
假设现在操作系统分配了两组地址:
第一组: 2,3, 4, 5, 6, 7, 8, 9
第二组: 2,3, 4, 5, 7, 9,10,11
显然,第一组的地址是连续的,因为对于每个地址的下一个地址都是其相邻地址
然而,第二组的地址是间断的,因为其中地址为5的下一个地址是7,地址为7的下一个地址为9,给的地址并不都是相邻的地址。
什么是存储单元?
以8位二进制作为一个存储单元,也就是一个字节。在计算机中最小的信息单位是bit,也就是一个二进制位,8个bit组成一个Byte,也就是字节。一个存储单元可以存储一个字节。
线性表中的数据元素占用的存储单元是多大?
不同数据类型所占用的存储单元大小不同,数据类型可以是基本数据类型,也可以是用户自定义的类。可以用sizeof()函数类获取数据类型所占用的存储单元的大小。
每个数据元素所占用的存储单元大小相同吗?
当然相同,因为线性表的定义是具有相同数据类型的n(n≥0)个数据元素的有限序列,其中n为表长。既然是每个元素是相同数据类型,所以每个数据元素所占用的存储单元大小相同。
1.3 线性表的顺序存储(代码描述)
1)静态分配
#define MaxSize 50 //定义线性表的最大长度
typedef struct{
ElemType data[MaxSize]; // 顺序表的元素
int length; // 顺序表的当前长度
}SqList; // 顺序表的类型定义
静态分配的特点:数组的大小和空间事先已经固定,一旦空间占满,再加入新的数据将会产生溢出,进而导致程序崩溃。
2)动态分配
#define InitSize 100 //表长度的初始定义
typedef struct{
ElemType *data; //指示动态分配数组的指针
int MaxSize,length; //数组的最大容量和当前个数
}SeqList; //动态分配数组顺序表的类型定义
动态分配的特点:存储数组的空间是在程序执行过程中通过动态存储分配语句分配的,一旦数据空间占满,就另外开辟一块更大的存储空间,用以替换原来的存储空间,从而达到扩充存储数组空间的目的,而不需要为线性表一次性地划分所有空间。
C的初始动态分配语句:
L.data = (ElemType*)malloc(sizeof(ElemType)*InitSize);
C++的初始动态分配语句:
L.data = new ElemType[InitSize];
注意:动态分配并不是链式存储,它同样属于顺序存储结构,物理结构没有变化,依然是随机存取方式,只是分配的空间大小可以在运行时决定。
顺序表的特点
1)主要特点是 随机访问,即通过首地址和元素序号可在时间O(1)内找到制定的元素。
例如,已知数组a[10],数组名a表示首地址,找到元素序号为0的元素可以通过a[0]获得,找到元素序号为9的元素可以通过a[9]获得。
2)存储密度高,每个结点只存储数据元素。
例如,比如链式存储,每个结点除了要存储数据元素,还要存储必要的指针,以获得相邻元素所在的地址。
3)逻辑上相邻的元素物理上也相邻,所以插入和删除需要移动大量元素。
例如,对于长度为10的数组,要在序号为5的元素前插入一个新元素,那么从包括序号为5的元素开始的元素都要后移1位。
2. 顺序表上基本操作的实现
1. 插入操作
bool ListInsert(SqList &L,int i,ElemType e){
if(i<1||i>L.length+1) //判断i的范围是否有效
return false;
if(L.length>=MaxSize) //当前存储空间已满,不能插入
return false;
for(int j=L.length;j>=i;j--) //将第i个元素及之后的元素后移
L.data[j]=L.data[j-1];
L.data[i-1]=e; //在位置i处放入e
L.length++; //线性表长度加1
return true;
}
平均时间复杂度为 O(n)
2. 删除操作
bool ListDelete(SqList &L,int i,Elemtype &e){
if(i<1 || i > L.length) //判断i的范围是否有效
return false;
e=L.data[i-1]; //将被删除的元素赋值给e
for(int j=i;j<L.length;j--) //将第i个位置后的元素前移
L.data[j-1]=L.data[j];
L.length--; //线性表长度减1
return true;
}
平均时间复杂度为O(n)
3.按值查找(顺序查找)
int LocateElem(SqList L,ElemType e){
int i;
for(i=0;i<L.length;i++){
if(L.data[i] == e)
return i+1; // 下标为i的元素值等于e,返回其位序i+1
return 0; // 退出循环,说明查找失败
}
平均时间复杂度为O(n)