目录
2.2.1 顺序表的定义
顺序表用一组地址连续的存储单元依次存储线性表中的数据元素,从而使逻辑上相邻的两个元素在物理位置上也相邻。通常用数组来描述,注意线性表中元素的位序是从1开始的,而数组中元素的下标是从0开始的。
表起始位置称为表头,表结束位置成为表尾。
1. 顺序表的静态分配
静态分配会事先确定好数组的大小与空间,一旦空间占满,新入的数据就会溢出引发异常,不够灵活。
#define MaxSize 10 //定义最大容量
typedef struct //类型重命名
{
ElemType data[MaxSize]; //存放数据
int length; //当前长度
} Sqlist; //结构体名:Sqlist
2. 顺序表的动态分配
动态分配存储数组的空间是程序执行过程中通过动态分配语句分配的,并不是链式存储,同样属于顺序存储结构,只是分配的空间可以在运行是动态决定。
#define InitSize 10 //定义初始容量
typedef struct //类型重命名
{
ElemType *data; //指针指向首元素首地址
int Maxsize; //顺序表最大容量
int length; //当前长度
} Sqlist; //结构体名:Sqlist
动态分配顺序表初始化
C 库函数 void *malloc(size_t size) 分配所需的内存空间,分配的内存大小至少为size参数所指定的字节数,malloc的返回值是一个指针,指向一段可用内存的起始地址。
void InitList(Sqlist *L) //初始化
{
L->data = (int *)malloc(sizeof(int) * InitSize);
L->length = 0; //初始长度为0
L->Maxsize = InitSize; //当前表的最大容量
}
动态分配下,一旦数据空间占满,就可以另外开辟一块更大的空间,并替换原来的存储空间,从而达到扩容的目的。
void IncreaseSize(Sqlist *L, int len){
int *p = L->data;
L->data = (int *)malloc(sizeof(int) * (L->Maxsize + len));
for (int i = 0; i<L->length; i++)
L->data[i] = p[i];
L->Maxsize = InitSize + len; //当前表的最大容量
free(p);
}
2.2.2 基本操作
1. 插入操作(从待查位置向队尾往后移动)
在顺序表L的第i(1 <= i <= L.length+1)个位置插入新元素e,移动元素最多的情况是在表头(i=1)插入,此时将所有的n个元素全部依次从最开始的队头元素往后移动一位,此时时间复杂度是O(n);移动元素最少的情况是在队尾(i=n+1)插入,j>=i语句不成立,元素后移语句不执行,时间复杂度是O(1)。若i的插入不合法,则返回false,表示插入失败;否则,将第i个元素以及后面的所有的元素往后移动一个元素,对应 L.data[j] = L.data[j-1],腾出一个空位置给e,并将顺序表长度+1,插入成功,返回true。
bool ListInsert(SqList &L,int i,ElemType e)
{
if(i<1||i>L.length+1)//判断要插入的位置是否合法
return false;
if(L.length>=MaxSize)//超出空间了
return false;
for(int j=L.length;j>=i;j--)//移动顺序表中的元素
L.data[j]=L.data[j-1];
L.data[i-1]=e;//数组下标从零开始,插入第一个位置,访问的下标为0
L.length++;
return true;
}
i表示插入的具体位置,位序从1开始,因此至少需要从1开始插入;length表示当前表中拥有元素的个数,也就是顺序表的表长,最多可以插入到表尾即L.length+1的位置,总共就n+1个插入结点。
在for循环中时,此时我们就要考虑数组下标和位序的关系了。j代表的是数组下标,虽然for循环中定义 j=L.length,但是它映射到数组时候对应为L.length-1(数组下标从0开始,对应位序减1),代表从数组最后一个元素开始,不断交换数据直到位置i(对应数组下标i-1)数据为空,再将e赋给数组L.data[i-1]的位置,完成在第i个位置上插入e的目的。
区别顺序表的位序与数组下标https://www.cnblogs.com/liusanjian/p/13304262.html?ivk_sa=1024320u
2. 删除操作(从待插位置向队头往前移动)
删除顺序表L中第 i (1 <= i <= L.length) 个位置的元素,再由变量返回,最好的情况是删除队尾元素,最坏的情况是删除队头的元素,需要将后面的n-1和元素全部从后往前移动一位,覆盖队头元素,并将表长减1。若i的输入位置不合法,则返回false;否则,将被删元素赋给引用变量e,移动元素后返回true。
bool ListDelete(SqList &L,int i,ElemType &e){
if(i<1||i>L.length)//如果删除的位置是不合法
return false;
e=L.data[i-1];//获取顺序表中对应的元素,赋值给e
for(int j=i;j<L.length;j++)
L.data[j-1]=L.data[j];
L.length--;//删除一个元素,顺序表长度减1
return true;
}
删除只能删除第一个元素(i=1)和最后一个元素(i=L.length),将第i个位置赋给j,其对应的数组下标就是j-1,直接用后面的元素L.data[j]覆盖。
3. 按值查找(顺序查找)
在顺序表中查找第一个元素值等于e的元素,并返回其位序(对应数组下表加1)。
int LocateElem(SqList L,ElemType e)
{
int i;
for(i=0;i<L.length;i++)
if(L.data[i]==e)
return i+1;//加1就是元素在顺序表中的位置
return 0;
}
完整可运行C语言程序:
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 50
typedef int ElemType;
//静态分配
typedef struct{
ElemType data[MaxSize];
int length;//当前顺序表中有多少个元素
}SqList;
//动态分配
#define InitSize 100
typedef struct{
ElemType *data;
int capacity;//动态数组的最大容量
int length;
}SeqList;
//i代表插入的位置,从1开始,e要插入的元素
bool ListInsert(SqList &L, int i, ElemType e)
{
if(i<1||i>L.length+1)//判断要插入的位置是否合法
return false;
if(L.length>=MaxSize)//超出空间了
return false;
for(int j=L.length;j>=i;j--)//移动顺序表中的元素
L.data[j]=L.data[j-1];
L.data[i-1]=e;//数组下标从零开始,插入第一个位置,访问的下标为0
L.length++;
return true;
}
//删除使用元素e的引用的目的是拿出对应的值
bool ListDelete(SqList &L,int i,ElemType &e)
{
if(i<1||i>L.length)//如果删除的位置是不合法
return false;
e=L.data[i-1];//获取顺序表中对应的元素,赋值给e
for(int j=i;j<L.length;j++)
L.data[j-1]=L.data[j];
L.length--;//删除一个元素,顺序表长度减1
return true;
}
//查找成功,返回位置,位置从1开始,查找失败,返回0
int LocateElem(SqList L,ElemType e)
{
int i;
for(i=0;i<L.length;i++)
if(L.data[i]==e)
return i+1;//加1就是元素在顺序表中的位置
return 0;
}
//打印顺序表元素
void PrintList(SqList &L)
{
for(int i=0;i<L.length;i++){
printf("%4d",L.data[i]);
}
printf("\n");
}
int main()
{
SqList L;//顺序表的名称
bool ret;//查看返回值,布尔型是True,或者False
ElemType del;//要删除的元素
//首先手动在顺序表中赋值
L.data[0]=1;
L.data[1]=2;
L.data[2]=3;
L.length=3;//总计三个元素
ret=ListInsert(L,2,60);
if(ret){
printf("插入成功\n");
PrintList(L);
}else{
printf("插入失败\n");
}
ret=ListDelete(L,1,del);
if(ret){
printf("删除成功\n");
printf("删除元素值为 %d\n",del);
PrintList(L);
}else{
printf("删除失败\n");
}
ret=LocateElem(L,60);
if(ret){
printf("查找成功\n");
printf("元素位置为 %d\n",ret);
}else{
printf("查找失败\n");
}
return 0;
}