顺序表
顺序表的定义
线性表的顺序存储又称顺序表。它是用一组地址连续的存储单元依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。
顺序表的特点是表中元素的逻辑顺序与其物理顺序相同。所以插入和删除操作需要移动大量元素。
线性表的顺序存储结构是一种随机存取的存储结构。
假定线性表的元素类型为ElemType,则线性表的顺序存储类型描述为
#define MaxSize 50 //定义线性表的最大长度
typedef struct{
ElemType data[MaxSize]; //用静态的“数组”存放数据元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义(静态分配方式)
//基本操作-初始化一个顺序表
void InitList(SqList &L){
for(int i=0; i<MaxSize; i++)
L.data[i]=0; //将所有数据元素设置为默认初始值
L.length=0; //顺序表初始长度为0
}
int main(){
SqList L; //声明一个顺序表
InitList(L); //初始化顺序表
//....未完待续,后续操作
return 0;
}
一组数据是可以静态分配的,也可以是动态分配的。在静态分配时,由于数组的大小和空间实现已经固定,一旦空间占满,再加入新的数据就会溢出,进而导致程序
而在动态分配时,存储数组的空间大小是在程序执行过程中通过动态分配语句分配的。
#define InitSize 100 //表长度的初始定义
typedef struct{
ElemType *data; //指示动态分配数组的指针,指向顺序表中第一个数据元素
int MaxSize; //顺序表的最大容量
int length; //顺序表的当前长度
}SeqList; //顺序表的类型定义(动态分配方式)
void InitList(SeqList &L){
//用malloc函数深情一片连续的存储空间
L.data=(int *)malloc(InitSize*sizeof(int));
L.length=0;
L.MaxSize=InitSize;
}
//增加动态数组的长度
void IncreaseSize(SeqList &L, int len){
int *p=L.data;
L.data=(int *)malloc(InitSize*sizeof(int));
for(int i=0; i<L.length; i++){
L.data[i]=p[i]; //将数据复制到新区域(时间开销大)
}
L.MaxSize=L.MaxSize+len; //顺序表最大长度增加 len
free(p); //malloc和free函数需要使用头文件 #include <stdlib.h>
}
int main(){
SeqList L; //声明一个顺序表
InitList(L); //初始化顺序表
//...往顺序表中随便插入几个元素...
IncreaseSize(L, 5);
return 0;
}
c的初始动态分配语句为
L.data=(ElemType *)malloc(sizeof(ElemType)*InitSize);
//(ElemType*):malloc函数返回一个指针,需要强制转型为你定义的数据元素类型指针
//sizeof(ElemType):一个数据元素所占存储空间的大小,如int占4个字节
//malloc函数的参数,指明要分配多大的连续内存空间
c++的初始动态分配语句为
L.data=new ElemType[InitSize];
Key:动态申请和释放内存空间
c—malloc、free函数
c++—new、delete关键字
顺序表的特点
- 随机访问,即可在o(1)时间内找到第i个元素
- 存储密度高,每个节点只存储数据元素
- 拓展容量不方便(即便采用动态分配的方式实现,拓展长度的时间复杂度也比较高)
- 插入删除操作不方便,需要移动大量元素
顺序表的基本操作-插入
ListInsert(&L,i,e):插入操作。在表L中的第i个位置(位序)上插入指定元素e。
#define MaxSize 10 //定义线性表的最大长度
typedef struct{
ElemType data[MaxSize]; //用静态的“数组”存放数据元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义(静态分配方式)
void ListInsert(SqList &L,int i,int e){ //在L的位序i处插入元素e
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
}
//插入的元素要合法,于是ListInsert函数改版为
bool ListInsert(SqList &L,int i,int e){
if(i<1||i>L.length+1) //判断i的范围是否有效
return false;
if(L.length>=MaxSize) //当前存储空间已满,不能插入
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;
//好的算法,应该具有“健壮性”。能处理异常情况,并给使用者反馈
}
int main(){
SqList L; //声明一个顺序表
InitList(L); //初始化顺序表
//...此处省略一些代码,插入几个元素
ListInsert(L,3,3);
return 0;
}
插入操作的时间复杂度:关注最深层循环语句的执行次数与问题规模n的关系。问题规模n=L.length(表长)
顺序表的基本操作-删除
ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素。并用e返回删除元素的值。
bool Delete(SqList &L,int i,int &e){
//为什么是int &e,而不是int e: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.leng--; //线性表的长度减1
return true;
}
int main(){
SqList L; //声明一个顺序表
InitList(L); //初始化顺序表
//...此处省略一些代码,插入几个元素
int e = -1; //用变量e把删除的元素“带回来”
if(ListDelete(L,3,e))
printf("已删除第3个元素,删除元素值为=%d\n",e);
else
print("位序i不合法,删除失败\n");
return 0;
}
删除操作的时间复杂度:关注最深层循环语句的执行次数与问题规模n的关系。问题规模n=L.length(表长)
顺序表的基本操作-查找
查找分为按位查找与按值查找。
顺序表的按位查找
GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。
#define MaxSize 10 //定义线性表的最大长度
typedef struct{
ElemType data[MaxSize]; //用静态的“数组”存放数据元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义(静态分配方式)
ElemType GetElem(SqList L,inti){
return L.data[i-1]; //时间复杂度o(1)
}
#define InitSize 10 //表长度的初始定义
typedef struct{
ElemType *data; //指示动态分配数组的指针,指向顺序表中第一个数据元素
int MaxSize; //顺序表的最大容量
int length; //顺序表的当前长度
}SeqList; //顺序表的类型定义(动态分配方式)
ElemType GetElem(SqList L,inti){
return L.data[i-1]; //时间复杂度o(1)
}
顺序表的按值查找
LocateElem(L,e):按值查找操作。在表L中查找具有给定关键字值的元素。
#define InitSize 10 //表长度的初始定义
typedef struct{
ElemType *data; //指示动态分配数组的指针,指向顺序表中第一个数据元素
int MaxSize; //顺序表的最大容量
int length; //顺序表的当前长度
}SeqList; //顺序表的类型定义(动态分配方式)
//在顺序表L中查找第一个元素值等于e的元素,并返回其位序
int LocateElem(SeqList L,ElemType e){
for(int i=0; i<L.length; i++)
if(L.data[i]==e)
return i+1; //数组下标为i的元素值等于e,返回其位序i+1
return 0; //退出循环,说明查找失败
}