文章目录
复习重点
线性表在算法题中经常出现,因为实现起来容易而且代码量并没有很多,注意在实现的时候考虑算法的时间复杂度和空间复杂度。
一、线性表的定义和基本操作
1.线性表的定义
线性表是具有相同数据类型的n(n≥0)个数据元素的有限序列。线性表一般表示为 L = ( a 1 , a 2 , a 3 , … … , a n ) L=(a_1,a_2,a_3,……,a_n) L=(a1,a2,a3,……,an),
其中,a1为表头元素,an为表尾元素,除了表头元素,每个元素有且仅有一个直接前驱,除了表尾元素,每个元素有且仅有一个直接后继。
以下为线性表的某些特点:
★表是有限的,即n不能是无限大。
★表中的元素是有逻辑上的顺序性。(记得上一章提到过链表的话是不遵循物理地址存储空间上的顺序性的,所以对于线性表只能有逻辑上的顺序性)
★表中的数据类型都相同,这意味着每个元素占有相同大小的存储空间。
1.线性表的基本操作
InitList(&L):初始化线性表。
Length(L):求表长。
LocateElem(L,e):查找表中等于e的元素。
GetElem(L,i):查找表中第i个元素的值并返回。
ListInsert(&L,i,e):在表中第i个位置插入元素e,并返回新表。
ListDelete(&L,i,&e):在表中删除第i个元素,并用e来返回删除的元素,同时返回新表。
PrintList(L):打印线性表L。
IsEmpty(L):线性表是否为空,是则返回true,否则返回false。
DestroyList(&L):销毁线性表,释放L所占用的空间。
附:个人觉得对于线性表的这些操作记得有就行,基本不会考这些基本操作的具体实现,一般都是可以直接使用的,在不给你这些基本操作名的时候,可以自己申明但是尽量写的和上述差不多。比如IsEmpty可以写成Empty,ListDelete可以写Del_List,都是没什么太大问题的。
二、线性表的顺序表示
1.什么是顺序表
简单来说,顺序表就是线性表(逻辑结构)的顺序存储(存储结构),也就是说顺序表就是一个数据结构了,还记得上一篇提到的顺序存储的特点吗,逻辑上相邻的元素存储的物理地址空间上也相邻,所以顺序表是用一组地址连续的存储单元来依次存放线性表中的数据元素。
注意线性表中元素的位序从1开始,数组下标从0开始。
顺序表的存储类型可以定义为如下:
#define MaxSize 20 //定义线性表的最大长度
typedef struct
{
ElemType data[MaxSize]; //元素
int length; //顺序表当前长度
}SqList; //顺序表类型
当然也可以定义如下:
#define InitSize 100 //初始表大小
typedef struct
{
ElemType *data; //动态分配数组的指针
int MaxSize,length; //最大长度和当前长度
}SeqList; //动态分配数组的顺序表的类型定义
对于C语言,初始的动态分配语句为:
SeqList L;
L.data=(ElemType *)malloc(sizeof(ElemType)*InitSize);
对于C++,初始的动态分配语句为:
SeqList L;
L.data=new ElemType[InitSize]
!!!注意:动态分配虽然有指针但不是链式存储,同样属于顺序存储结构,只是分配的空间大小可以在运行时动态决定。
2.顺序表上基本操作的实现
(1)插入操作代码如下,(1<=i<=L.length+1):
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]; //第i个元素之后所有元素右移
L.data[i-1]=e; //将第i个元素赋值为e
L.length++; //插入后表长+1
return true; //插入成功!
}
注意:在判断插入位置合法时为length+1是因为在表的末尾插入就是length+1
最好情况:表尾插入元素,不需要右移元素,直接赋值即可,时间复杂度为O(1);
最差情况:表头插入元素,全部元素右移,时间复杂度为O(n);
平均情况:时间复杂度为O(n/2)。
(2)删除操作代码如下,(1<=i<=L.length):
bool ListDelete(SqList &L,int i,ElemType &e){
if