第一次数据结构笔记(线性表的基本操作)
我们实际上是使用一维数组来描述线性表的
1. 线性表的顺序存储结构:
#define MAXSIZE 20
typedef int ElemType;
//typedef是自定义类型,在这里就是把ElemType自定义成int,在后面看见ElemType实际上就相当于int
typedet struct
{
ElemType data[ MAXSIZE ] ; //这里实际上就是定义了一个int型数组,叫data,大小为MAXSIZE
int length ;
//length问题:在后面会直接引用线性表L和他的长度length,不要感到迷惑,
//因为在后面的线性表L实际上是已经赋过初值的了,在赋初值时,每输入一个数据,length就+1,
//这样就可以用length来描述线性表的长度了
}SqList ;
2. 地址计算方法
LOC( ai ) = LOC( a1 ) + ( I - 1 ) * C
3.获得元素
#define ok 1;
typedef int Status ;
Status GetElem (Sqlist L ; int i , Elemtype *e)
//i为查找位置,*e用于返回找到的值,ElemType *e实际上就是定义了一个int型指针;
//为什么用指针*e返回值而不用return?因为我们需要return来返回代码运行结果(ERROR还是OK),
//但是return只能返回一个值,所以我们就需要使用指针来返回我们找到的值
{
if ( L.length == 0 || i < 1 || i > L.length) //判断查找位置是否合理
{
return ERROR;
}
*e = L . data [ i - 1 ] ;
//因为顺序表和数组数据位置始终相差1,虽然是顺序表,但是他的本质其实还是一维数组,所以顺序表中第i个数据实际上就是数组中第i-1个数据。
return ok;
}
4.插入操作
插入思路:
1.如果插入位置不合理,抛出异常。
2.如果线性表长度等于数组长度,则抛出异常或动态增加数组容量(代码效率会变低)。
3.从最后一个元素开始向前遍历到第 i 个位置,分别将他们都向后移动一个位置。(空出第 i 个位置)
4.将要插入元素填入位置 i 处。
5.线性表长度+1。
//插入操作不需要考虑线性表是否为空,为空也可以插入,但是需要考虑线性表是否达到最大长度
Status ListInsert ( SqList *L , int i , ElemType e)
//这里需要对线性表做出改变,且需要将这种改变传回顺序表,
//所以需要用*L(结构指针)来返回改变的值到顺序表中
//这里e仅仅起到记录需要插入的元素的作用,不需要返回数值,所以不用指针,用int型数据e
{
int k;
if(L -> length == MAXSIZE) //判断线性表是否达到数组最大值
{
return ERROR;
}
if( i < 1 || i > L->length + 1)
//判断插入卫视是否不合理 i<1 或者插入位置 i 大于现阶段线性表长度
{
return ERROR;
}
if( i <= L ->length) //当插入位置不在表尾时,如果在表尾,直接length--即可。
{
for( k = L -> length - 1; k >= i-1; k- -)
//因为我们要插入一个数据,所以需要从最后一位开始向后挪动,给需插入元素留位置。
//length-1是因为在这里我们操作的对象实际上时数组,线性表的最后一个数据处于末尾length处,
//所以在数组中,最后一个元素就处于length-1;
{
L ->data[ k+1 ] = L->data[ k ];
//将最后一个到第 i 个之前的所有元素向后挪,给需要插入的元素留位置。
}
}
L ->data[i - 1] = e; //将新元素插入
L ->length++; //线性表长度+1
return ok;
}
5.删除操作
操作思路:
1.`如果位置不合理(为空表),返回异常
2.取出删除元素。
3.从删除元素位置开始遍历到最后一个元素位置,分别将她们都向前按移动一个位置。
4.表长 - 1.
//删除操作不需要考虑顺序表是否达到最大长度,因为即使达到最大长度,依旧可以删除,但是顺序表不能为空,为空没办法删除,所以需要判断线性表是否为空而不需要判断线性表是否已满
Status ListDelete (SqList *L, int i, ElemType *e)
//删除操作需要对顺序表L做出改变,且需要将这种改变传回顺序表,所以用结构指针*L
//用指针*e来返回删除的值
{
int k;
if ( L->length == 0)//当顺序表不为空时
{
return ERROR;
}
if ( i < 1 || i > L-> length)
//判断查找位置是否合乎情理
{
return ERROR;
}
*e = L->data[ i - 1] ;
//返回需要删除的第i个数据
//在线性表中是第i个,在数组中是第i-1个,这里我们的操作对象实际上数组
if ( i < L -> length )//当删除位置不处于线性表末尾时
{
for( k = i; k < L-> length ; k++)
//将从第 i 个数据到最后一个数据向前挪动
{
L - >data[ k - 1] = L -> data[ k ];
}
//后一位向前移
}
L-> length - - ;
//删除之后线性表长度 - 1
return OK ;
}
PS:1.最坏的情况如果要插入或者删除的位置时
第一个元素,那就意味着要移动所有的元素,所以时间复杂度时O(n)。
2.最好的情况插入和删除操作刚好在最后一个位置操作,因为不需要移动任何元素,所以此时时间复杂度为O( 1 );
线性顺序存储结构的优缺点:
1。优点:不用为了表示表中元素之间的逻辑关系而增加额外的存储空间。
2.有点:可以快速存取表中任意位置的元素。
3.缺点:插入和删除操作需要移动大量元素。
4.缺点:当线性表长度变化较大时,难以确定存储空间的容量。
5.缺点:容易造成存储空间的碎片(申请空间是一整块一整块的申请的)。