线性表(顺序表)——基本操作/实现
线性表(顺序表)——基本操作/实现
线性表定义和特点及常用类型定义
-
定义:数据类型相同的n个元素构成的有限序列
#所有呈递增关系的整数不属于线性表(无限)
-
特点:线性表是线性结构,线性结构的基本特点是:除第一个元素无直接前驱,最后一个元素无直接后继外,其他每个数据元素都有一个前驱和后继
-
位序:线性表中 第i个 元素,它的位序是从 1 开始的(区别数组下标从 0 开始)
#用数组实现线性表时注意审题
-
常用类型定义:
- InitList(&L):初始化
- DestroyList(&L):销毁
- GetElem(L,i):按位置查找。获取表L中的第i个元素
- LocateElem(L,e):按值查找
- InsertLIst(&L,i):插入
- DeleteList(&L,i):删除
- Length(L):求表长。表L中数据元素的个数
- PrintList(L):输出。按从前到后的顺序输出表中数据
- Empty(L):判空。空表返回true,否则返回false
-
关于 & :如果调用函数时,需要将函数中参数修改的结果带回来,则使用“&”,如:线性表的初始化,销毁,插入,删除等。
顺序表定义和基本操作及特点
-
定义:按顺序存储的线性表
-
基本操作:
静态分配——使用数组
#definde MaxSize 10;//数组大小 typedef struct{ ElemType data[MaxSize]; /*ElemType 是数据元素类型,在自己使用时 换成相应的数据元素类型即可,如int,string,double等*/ int length; }SqList;//类型定义(别名) //初始化一个顺序表 void InitList(SqList &L){ for(int i=0;i<MaxSize;++i) L.data[i]=0;//设置数据元素为默认值0(可省略) L.length=0;//顺序表的初始长度 } int main(int argc, char** argv) { SqList L;//声明一个顺序表 InitList(L); //初始化顺序表 ....... return 0; }
#设置数据元素为默认值0虽然可以省略,但是如果没有设置数据元素为默认值,内存中会有遗留的“脏数据”。
动态分配——使用指针
#definde InitSize 10;//数组大小 typedef struct{ int *data;//动态分配数组的指针 int MaxSize;//顺序表最大容量 int length;//顺序表当前长度 }SqList;//类型定义(别名) //初始化一个顺序表 void InitList(SqList &L){ L。data = (int *)malloc(sizeof(ElemType)*InitSize); /*动态申请分配内存 (int *)使malloc函数返回的指针 强制转换为自己所需的数据元素类型指针 InitSize 指明要分配多大的空间,sizeof()中 * 是乘号 */ L.length=0;//顺序表的初始长度 L.MaxSize = InitSize; } //增加动态数组的长度 void IncreaseSize(SqList &L,int len){ int *p = L.data;//将L中数据先暂存在p中; //扩容 L.data = (int *)malloc(sizeof(int)*L.MaxSize+len); for(int i=0;i<L.length;++i) L.data[i]=p[i] ;//将数据复制到新区域 L.MaxSize = L.MaxSize+len;//增加表长 free(p);//释放原内存空间P; }
#动态分配内存扩容虽然要方便一点,但是由于要将原内存的数据复制,所以时间开销会很大。
-
特点:
- 随机访问(随机存取)。查询第i个元素,data[i-1],因为线性表的位序是从1开始的,数组下标是从0开始,所以是 i-1
- 存储密度高
- 拓展容量不方便
- 插入,删除数据不方便
顺序表的插入和删除——基于静态分配
声明和初始化:
#definde MaxSize 10;//数组大小
typedef struct{
int data[MaxSize]//数组
int length;//顺序表当前长度
}SqList;//类型定义(别名)
void InitList(SqList &L){
for(int i=0;i<MaxSize;++i)
L.data[i]=0;//设置数据元素为默认值0(可省略)
L.length=0;//顺序表的初始长度
}
插入
void ListInsert(SqList &L,int i,int e){
if(i<1||i>L.length+1)//判断i的范围是否有效
return "输入i的范围无效";
if(L.length>=MaxSize)//如果当前存储空间已满,不能插入
for(int j=L.length;j>=i;--j)
L.data[j]=L.data[j-1];//将第i个元素及之后的元素后移
L.data[i-1]=e;//在位置i处放入e
++L.length;//长度加1
}
int main(int argc, char** argv) {
SqList L;//声明一个顺序表
InitList(L); //初始化顺序表
......
ListInsert(L,3,3);//插入
return 0;
}
插入的时间复杂度
删除
bool ListDelete(SqList &L,int i,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)
L.data[j-1]=L.data[j];//将第i个位置后的元素前移
--L.length;//长度减1
}
int main(int argc, char** argv) {
SqList L;//声明一个顺序表
InitList(L); //初始化顺序表
......
int e=-1;
if(ListDelete(L,3,e))
printf("已经删除第3个元素,删除元素值为=%d\n",e);
else
printf("位序i不合法,删除失败\n");
return 0;
}
删除的时间复杂度
顺序表的查找
按位查找:获取表L中第i个位置 的元素的值
-
静态分配
ElemType GetElem(SqList L,int i) //ElemType为你所需的返回值类型 { if(i<1||i>L.length)//判断i的范围是否有效 return “位序i不合法,查找失败\n”; return L.data[i-1]; }
-
动态分配
和访问数组的方法一样,同上。
按值查找:获取表L中具有给定关键字值得元素
//在顺序表L中查找第一个元素值等于e的元素,并返回其位序
int LocateElem(SqList L,int e){
for(int i=0;i<L.length;++i)
if(L.data[i]==e)//“==”针对于基本数据类型
return i+1;
return 0;
}
#如果是结果类型的数据元素进行比较是需要依次对比各个分量来判断结构体是否相等