线性表:具有相同特性的数据元素(既同类型数据)的一个有限序列.
注:同一线性表中的元素必定具有相同特性
线性表的特性:1.有穷性 2.一致性 3.序列性
线性表的最本质特征:有唯一的前驱和后继
线性表的顺序存储结构———顺序表
顺序存储结构——逻辑上相邻的元素,在物理上也相邻
在c语言中,顺序表通常用数组来存储,这与python中的列表不同,数组是给定长度的,数组中元素的地址也是相邻的,且数组中的元素类型一定要相同,而列表list是的长度理论上是可以无限添加的,(因为python内部已经帮我们实现了),列表中的元素类型也开始是不同的,且列表中各元素的可以是任意的。
言归正传,c语言中的顺序表采用数组来实现:
c语言顺序表的基本操作,涉及以下操作:
1.初始化顺序表
2.销毁:顺序存储不存在销毁操作
3.判断顺序表是否为空
4.求顺序表长度
5.输出顺序表元素
6.取值,取出顺序表的某一个值
7.查找,查看某一个值是否在顺序表中
8.插入,在指定位置插入数据,后续元素向后移动,长度增加
9.删除,删除指定位置的数据,后续元素向前移动,长度减小
在顺序表中,为了简单,假设ElemType为int类型,还有一个length来记录顺序表的长度,SQList类型声明如下:
#define MAXSIZE 128
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE];//存储线性表的元素值
int length;//存储线性表的元素个数
}SQList;
1)初始化顺序表
初始化,构造一个空的线性表 ,代码如下:
SQList InitList()
{
SQList l;
l.length=0;
return l;
}
2) 销毁顺序表
顺序存储不存在销毁操作
3)判断顺序表是否为空
若顺序表为空,返回1,否则返回0,上面SQList我们已经有了一个lenght,并且在初始化中已经将lenght赋予0,这里只需要判断lenght的值便可以确定顺序表是否为空,代码如下:
int ListEmpty(SQList l)
{
if(l.length==0)
{
return 1;
}
else
{
return 0;
}
}
4)求顺序表长度
顺序表的长度就是lenght,代码如下:
int ListLength(SQList l)
{
return l.length;
}
5)输出顺序表元素
这里只需要用一个for循环,在加以一定条件即可,代码如下:
/*
元素的下标范围:0 -- length-1
*/
void DispList(SQList l)
{
int i;
printf("线性表的元素为:");
for(i=0;i<=l.length-1;i++)
{
printf("%d ",l.data[i]);
}
printf("\n");
}
6)取值
想要得到顺序表中的某个元素,这里需要判断顺序表是否为空、是否在顺序表的长度之类以确保参数合法性,代码如下:
/*
把线性表l中的第i个元素取出来,存储在*e中
参数合法性:i>=1&&i<=length
若参数合法,进行相关操作,并返回1;
否则,提示,返回0
*/
int GetElem(SQList l,int i,ElemType *e)
{
if(i>=1&&i<=l.length)
{
*e=l.data[i-1];
return 1;
}
else
{
printf("参数不合法!\n");
return 0;
}
}
7)查找
在线性表l中查找是否存在值为e的元素,若存在,返回该元素的位序(第几个);否则,返回0 ,若存在多个相同元素,只返回第一个的位序,代码如下:
int LocateElem(SQList l,ElemType e)
{
int i;
for(i=0;i<=l.length-1;i++)
{
if(l.data[i]==e)
{
return i+1;
}
}
return 0;
}
8)插入元素
在顺序表中的第i个位置,添加一个值为e的元素进去,这里需要将原来在第i个位置上的元素及其后面的元素都往后移动,还需要考虑参数i的合法性,参数合法性:i>=1&&i<=length+1 ,若参数合法,进行相关操作,并返回1;否则,提示,返回0,代码如下:
int ListInsert(SQList *l,int i,ElemType e)
{
int j;
if(i>=1&&i<=(*l).length+1)
{
//1.往后移动一个位置
/*
移动下标范围:i-1 -- length-1
*/
for(j=(*l).length-1;j>=i-1;j--)
{
(*l).data[j+1]=(*l).data[j];
}
//2.把元素添加进去
(*l).data[i-1]=e;
//3.长度+1
(*l).length=(*l).length+1;
return 1;
}
else
{
printf("参数不合法!\n");
return 0;
}
}
9)删除元素
把顺序表的第i个元素删除,并把删除的元素值存储到*e中,这里需要考虑参数i的合法性,参数合法性:i>=1&&i<=length ,若参数合法,进行相关操作,并返回1;否则,提示,返回0 ,删除以后还需要将原来在第i+1个位置上的元素及其后面的元素都往前移动,代码如下:
/*
把线性表l的第i个元素删除,并把删除的元素值存储到*e中
参数合法性:i>=1&&i<=length
若参数合法,进行相关操作,并返回1;
否则,提示,返回0
*/
int ListDelete(SQList *l,int i,ElemType *e)
{
int j;
if(i>=1&&i<=(*l).length)
{
//1.把第i个元素值存储到*e中
*e=(*l).data[i-1];
//2.往前移动一个位置
/*
移动下标范围:i -- length-1
*/
for(j=i;j<=(*l).length-1;j++)
{
(*l).data[j-1]=(*l).data[j];
}
//3.长度-1
(*l).length=(*l).length-1;
return 1;
}
else
{
printf("参数不合法!\n");
return 0;
}
}
总结:
在顺序表中插入元素所需移动元素的平均次数为:n/2,在顺序表中删除元素所需移动元素的平均次数为(n-1)/2,因此,插入和删除元素的时间复杂度都为O(n)
最后在附上完整代码:
#include
#define MAXSIZE 128
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE];//存储线性表的元素值
int length;//存储线性表的元素个数
}SQList;
/*
1.初始化
构造一个空的线性表
*/
SQList InitList()
{
SQList l;
l.length=0;
return l;
}
/*
2.销毁
顺序存储不存在销毁操作
*/
void DestroyList(SQList *l)
{
}
/*
3.判断线性表是否为空
若为空,返回1;
否则,返回0
*/
int ListEmpty(SQList l)
{
if(l.length==0)
{
return 1;
}
else
{
return 0;
}
}
/*
4.求长度
*/
int ListLength(SQList l)
{
return l.length;
}
/*
5.输出
元素的下标范围:0 -- length-1
*/
void DispList(SQList l)
{
int i;
printf("线性表的元素为:");
for(i=0;i<=l.length-1;i++)
{
printf("%d ",l.data[i]);
}
printf("\n");
}
/*
6.取值
把线性表l中的第i个元素取出来,存储在*e中
参数合法性:i>=1&&i<=length
若参数合法,进行相关操作,并返回1;
否则,提示,返回0
*/
int GetElem(SQList l,int i,ElemType *e)
{
if(i>=1&&i<=l.length)
{
*e=l.data[i-1];
return 1;
}
else
{
printf("参数不合法!\n");
return 0;
}
}
/*
7.查找
在线性表l中查找是否存在值为e的元素,
若存在,返回该元素的位序(第几个);
否则,返回0
备注:若存在多个相同的元素,只找第1个
*/
int LocateElem(SQList l,ElemType e)
{
int i;
for(i=0;i<=l.length-1;i++)
{
if(l.data[i]==e)
{
return i+1;
}
}
return 0;
}
/*
8.添加
在线性表l中的第i个位置,添加一个值为e的元素进去
参数合法性:i>=1&&i<=length+1
若参数合法,进行相关操作,并返回1;
否则,提示,返回0
*/
int ListInsert(SQList *l,int i,ElemType e)
{
int j;
if(i>=1&&i<=(*l).length+1)
{
//1.往后移动一个位置
/*
移动下标范围:i-1 -- length-1
*/
for(j=(*l).length-1;j>=i-1;j--)
{
(*l).data[j+1]=(*l).data[j];
}
//2.把元素添加进去
(*l).data[i-1]=e;
//3.长度+1
(*l).length=(*l).length+1;
return 1;
}
else
{
printf("参数不合法!\n");
return 0;
}
}
/*
9.删除
把线性表l的第i个元素删除,并把删除的元素值存储到*e中
参数合法性:i>=1&&i<=length
若参数合法,进行相关操作,并返回1;
否则,提示,返回0
*/
int ListDelete(SQList *l,int i,ElemType *e)
{
int j;
if(i>=1&&i<=(*l).length)
{
//1.把第i个元素值存储到*e中
*e=(*l).data[i-1];
//2.往前移动一个位置
/*
移动下标范围:i -- length-1
*/
for(j=i;j<=(*l).length-1;j++)
{
(*l).data[j-1]=(*l).data[j];
}
//3.长度-1
(*l).length=(*l).length-1;
return 1;
}
else
{
printf("参数不合法!\n");
return 0;
}
}
int main()
{
SQList InitList();
void DestroyList(SQList *l);
int ListEmpty(SQList l);
int ListLength(SQList l);
void DispList(SQList l);
int GetElem(SQList l,int i,ElemType *e);
int LocateElem(SQList l,ElemType e);
int ListInsert(SQList *l,int i,ElemType e);
int ListDelete(SQList *l,int i,ElemType *e);
//在使用之前,一定要初始化
SQList ll;
ll=InitList();
ListInsert(&ll,ListLength(ll)+1,100);
ListInsert(&ll,ListLength(ll)+1,200);
ListInsert(&ll,ListLength(ll)+1,300);
ListInsert(&ll,ListLength(ll)+1,400);
ListInsert(&ll,ListLength(ll)+1,500);
DispList(ll);
return 1;
}