一、顺序表的顺序存储表示
线性表的顺序存储表示又称为顺序存储结构或顺序映像。
顺序存储定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。
线性表的第1个数据元素ai的存储位置,称作线性表的起始位置或基地址。
例如:线性表(1,2,3,4,5,6)的存储结构:
依次存储,地址连续——中间没有空出存储单元。是一个典型的线性表顺序存储结构。
地址不连续——中间存在空的存储单元。不是一个线性表顺序存储结构。
线性表顺序存储结构占用一片连续的存储空间。知道某个元素的存储位置就可以计算出其他元素的存储位置。
顺序表中元素存储位置的计算
如果每个元素占用8个存储单元,ai存储位置是2000单元,则ai+1存储位置是? 2008单元
假设线性表的每个元素需占l个存储单元,则第i+1个数据元素的存储位置和第i个数据元素的存储位置之间满足关系:
LOC(ai+1) = LOC(ai) + l
由此,所有数据元素的存储位置均可由第一个数据元素的存储位置得到:
LOC(ai) = LOC(ai) + (i-1)*l
线性表的顺序存储结构示意图
顺序表的特点:以物理位置相邻表示逻辑关系。任一元素均可随机存取。(优点)
#define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量 typedef struct{ ElemType elem[LIST_INIT_SIZE]; int length; //当前长度 }SqList;
多项式的顺序存储结构类型定义
Pn(x) = p1xe1 + p2xe2 + ... + pmxem
线性表P = ((p1,e1),(p2,e2),...,(pm,em))
#define MAXSIZE 1000 //多项式可能达到的最大长度 typedef struct { //多项式非零项的定义 float p; //系数 int e; //指数 }Polynimial; typedef struct{ Polynimial *elem; //存储空间的基地址 int length; //多项式中当前项的个数 }SqList; //多项式的顺序存储结构类型为SqList
例如:图书表的顺序存储结构类型定义
#define MAXSIZE 10000 //图书表可能达到的最大长度 typedef struct { //图书信息定义 char no[20]; //图书ISBN char name[50]; //图书名字 float price; //图书价格 }Book; typedef struct { Book *elem; //存储空间的基地址 int length; //图书表中当前图书个数 }SqList; //图书表的顺序存储结构类型为SqList
二、顺序表中基本操作的实现
1、初始化
顺序表的初始化操作就是构造一个空的顺序表。
算法1 顺序表的初始化
【算法步骤】
①为顺序表L动态分配一个预定义大小的数组空间,使elem指向这段空间的基地址。
②将表的当前长度设为0。
【算法描述】
Status IniList(SqList &L) { //构造一个空的顺序表L L.elem = new ElemType[MAXSIZE]; //为顺序表分配一个大小为MAXSIZE的数组空间 if(!L.elem) exit(OVERFLOW); //存储分配失败退出 L.length = 0; //空表长度为0 return OK; }
动态分配线性表的存储区域可以更有效地利用系统的资源,当不需要该线性表时,可以使用销毁操作及时释放占用的存储空间。
2、取值
取值操作是根据指定的位置序号i,获取顺序表中第i个数据元素的值。
由于顺序存储结构具有随机存取的特点,可以直接通过数组下标定位得到,elem[i-1]单元存储第i个数据元素。
算法2 顺序表的取值
【算法步骤】
①判断指定的位置符号i值是否合理(1 ≤ i ≤ L.length),若不合理,则返回REEOR。
②若i值合理,则将第i个数据元素L.elem[i-1]赋给参数e,通过e返回第i个数据元素的传值。
【算法描述】
Status GetElem(SqList L,int i,ElemType &e) { if(i <1 || i > L.length) return ERROR; //判断i值是否合理,若不合理,返回ERROR e = L.elem[i-1]; //elem[i-1]单元存储第i个数据元素 return OK; }
【算法分析】
显然,顺序表取值算法的时间复发度为O(1)。
3、查找
查找操作是根据指定的元素值e,查找顺序表中第i个与e相等的元素。若查找成功,则返回该元素在表中的位置序号;若查找失败,则返回0。
算法3 顺序表的查找
【算法步骤】
①从第一个元素起,依次和e相比较,若找到与e相等的元素L.elem[i],则查找成功,返回该元素的序号i+1。
②若查遍整个顺序表都没有找到,则查找失败,返回0.
【算法描述】
int LocateElem(SqList L,ElemType e) { //在顺序表L中查找值为e的数据元素,返回其序号 for(i = 0;i < L.length;i++) if(L.elem[i] == e) return i+1; //查找成功,返回序号i+1 return 0; //查找失败,返回0 }
【算法分析】
当在顺序表中查找一个数据元素时,其时间主要消耗在数据比较上,而比较的次数取决于被查元素在线性表中的位置。
在查找时,为确定元素在顺序表中的位置,需和给定值进行比较的数据元素个数的期望值称为查找算法在查找成功时的平均查找长度(Average Search Length,ASL)。
假设每个元素的查找概率相等,即pi = 1/n
则
由此可见,顺序表按值查找算法的平均时间复杂度为O(n)。
4、插入
线性表的插入操作是指在表的第i个位置插入一个新的数据元素e,使长度为n的线性表(a1,...,ai-1,ai,...,an)变成长度为n+1的线性表(a1,...,ai-1,e,ai,...,an)
数据元素ai-1和ai之间的逻辑关系发生了变化。在线性表的顺序存储结构中,由于逻辑上相邻的数据元素在物理位置上也是相邻的,因此,除非i = n+1,否则必须移动元素才能反映这个逻辑关系的变化。
算法4 顺序表的插入
【算法步骤】
①判断插入位置i是否合法(i值得合法范围是l ≤ i ≤ n+1),若不合法则返回ERROR。
②判断顺序表的存储空间是否已满,若满则返回ERROR。
③将第n个至第i个位置的元素依次向后移动一个位置,空出第i个位置(i = n+1时无需移动)。
④将要插入的新元素e放入第i个位置。
⑤表长加1。
【算法描述】
Status ListInsert(SqList &L,int i,ElemType e) { //在顺序表L中第i个位置之前插入新的元素e,i值得合法范围是1 ≤ i ≤ L.length+1 if ((i<1) || (i > L.length + 1)) return ERROR; //i值不合法 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; }
上述算法没有处理表的动态扩充,因此当表长已经达到预设的最大空间时,则不能再插入元素。
【算法分析】
当在顺序表中某个位置上插入一个数据元素时,其时间主要耗费在移动元素上,而移动元素的个数取决于插入元素的位置。
假设pi是在第i个元素之前插入一个元素的概率,Eins为在长度为n的线性表中插入一个元素时所需移动元素次数的期望值(平均次数),则有
不失一般性,可以假定在线性表的任何位置上插入元素都是等概率的,即pi = 1/(n+1)
简化为
由此可见,顺序表插入算法的平均时间复杂度为O(n)。
5、删除
线性表的删除操作是指将表的第i个元素删去,将长度为n的线性表 (a1,...,ai-1,ai,ai+1,...,an)变成长度为n-1的线性表 (a1,...,ai-1,ai+1,...,an)
数据元素ai-1、ai和ai+1之间的逻辑关系发生了变化,为了在存储结构上反映这个变化,同样需要移动元素。
算法5 顺序表的删除
【算法步骤】
①判断删除位置i是否合法(合法值为1 ≤ i ≤ n),若不合法则返回ERROR。
②将第i+1个至第n个的元素依次向前移动一个位置(i = n时无需移动)。
③表长减1。
【算法描述】
Status ListDelete(SqList &L,int i) { //在顺序表L中删除第i个元素,i值得合法范围是1 ≤ i ≤ L.length if((i<1) || (i>L.length)) return ERROR; //i值不合法 for (j = i;j<= L.length-1;j++) L.elen[j-1] = L.elem[j]; //被删除元素之后的元素前移 --L.length; //表长减1 return OK; }
【算法分析】
当在顺序表中某个位置上删除一个数据元素时,其时间主要耗费在移动元素上,而移动元素的个数取决于删除元素的位置。
假设pi是删除第i个元素的概率,Edel为在长度为n的线性表中删除一个元素时所需移动元素次数的期望值(平均次数),则有
不失一般性,可以假定在线性表的任何位置上删除元素都是等概率的,即 pi = 1/n
简化为
由此可见,顺序表删除算法的平均时间复杂度为O(n)。
顺序表可以随机存取表中任一元素,其存储位置可用一个简单、直观的公式来表示。然而,从另一方面来看,这个特点也造成了这种存储结构的缺点:在做插入或删除操作时,需移动大量元素。另外由于数组有长度相对固定的静态特性,当表中数据元素个数较多且变化较大时,操作过程相对复杂,必然导致存储空间的浪费。所有这些问题,都可以通过线性表的另一种表示方法—链式存储结构来解决。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话