线性表是具有相同数据类型的 n ( n > 0 ) n(n>0) n(n>0)个数据元素的有限序列,其中 n n n为表长,当 n = 0 n=0 n=0时线性表是一个空表。线性表一般表示为 L = ( a 1 , a 2 , . . . , a i , . . . , a n ) L=(a_1,a_2,...,a_i,...,a_n) L=(a1,a2,...,ai,...,an)
几个概念:
a i a_i ai是线性表中的“第i个”元素在线性表中的位序。
a 1 a_1 a1是表头元素, a n a_n an是表尾元素。
除第一个元素外,每个元素有且仅有一个直接前驱;除最后一个元素外,每个元素有且仅有一个直接后继。
线性表的抽象数据类型定义
ADT{
数据对象: D D D={ a i ∣ a i ∈ E l e m S e t , i = 1 , 2 , 3 , . . . , n , n ≥ 0 a_i|a_i\in ElemSet,i=1,2,3,...,n,n\geq0 ai∣ai∈ElemSet,i=1,2,3,...,n,n≥0}
数据关系: R R R={ < a i − 1 , a i > ∣ a i − 1 , a i ∈ D , i = 2 , 3 , . . . n
基本操作:
InitList(&L)
操作结果:构造一个空的线性表L;
Destory(&L)
初始条件:线性表L已经存在
操作结果:销毁线性表L
ClearList(&L)
初始条件:线性表L已经存在
操作结果:将L重置为空表
ListEmpty(L)
初始条件:线性表L已存在
操作结果:若L为空表,则返回TRUE,否则返回FALSE
ListLength(L)
初始条件:线性表L已存在;
操作结果:返回线性表L中的数据元素个数;
GetElem(L,i,&e)
初始条件:线性表L已存在,1<=i<=ListLengh(L)
操作结果:用e返回L中第i个数据元素的值;
LocateElem(L,e)
初始条件:线性表L已存在
操作结果:返回L中第1个值与e相同的元素在L中的位置。若这样的数据元素不存在,则返回值为0。
PriorElem(L,cur_e,&pre_e)
初始条件:线性表L已存在
操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e 返回其前驱,否则操作失败, pre_e 无定义
NextElem(L,cur_e,&next_e)
初始条件:线性表L已存在
操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回其后继,否则操作失败, next_e无定义
ListInsert(L,i,&e)
初始条件:线性表L已存在,1≦i≦ListLength(L) +1
操作结果:在线性表L中的第i个位置之前插入新的元素e,L长度加1;
ListDelete(&l,i)
初始条件:线性表L已存在且非空,1≦i≦ListLength(L)
操作结果:删除L的第i个数据元素,L长度减1
TraverseList(L)
初始条件:线性表L已存在
操作结果:对线性表L进行遍历,在遍历过程中对L的每个 结点访问一次
}ADT List
顺序表——用顺序结构的方式实现线性表
特点:
①随机访问,即可以在 O(1) 时间内找到第 i 个元素。
②存储密度高,每个节点只存储数据元素。
③拓展容量不方便(即便采用动态分配的方式实现,拓展长度的时间复杂度也比较高)。
④插入、删除操作不方便,需要移动大量元素。
给各个数据元素分配连续的存储空间,大小为MaxSize*sizeof(ElemType)
“数组”存满后无法更改
#define MaxSize 10//定义最大长度
typedef struct {
ElemType data[MaxSize];
int length;
}SqList;
//初始化线性表
void Initlist(SqList &L){
L.length=0;
}
#define InitSize 10//定义最大长度
typedef struct {
ElemType *data;
int MaxSize;
int length;
}SqList;
//初始化线性表
void Initlist(SqList &L){
L.data=(ElemType *)malloc(InitSize*sizeof(ElemType));
L.length=0;
L.MaxSize=InitSize;
}
void IncreaseSize(SqList &L,int len){
int *p=L.data;
L.data=(ElemType *)malloc((L.MaxSize+len)*sizeof(ElemType));
for(int i=0;i<L.length;i++){
L.data[i]=p[i];//将数据复制到新区域
L.MaxSize=L.MaxSize+len;//顺序表最大长度增加1en
free(p);
}
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.lengthlj>=i;j--){
L.data[j]=L.data[j-1];
}
L.data[i-1]=e;
L.length++;
}
时间复杂度分析:
最好情况:新元素插入到表尾,不需要移动元素i = n+1,循环0次;最好时间复杂度 = O(1);
最坏情况:新元素插入到表头,需要将原有的 n 个元素全都向后移动i = 1,循环 n 次;最坏时间复杂度 = O(n);
平均情况:假设新元素插入到任何一个位置的概率相同,即 i = 1,2,3, … , length+1 的概率都是 p = 1 n + 1 p=\frac{1}{n+1} p=n+11,循环 n 次;i=2 时,循环 n-1 次;i=3,循环 n-2 次 …… i =n+1时,循环0次。平均循环次数 = n p + ( n − 1 ) p + ( n − 2 ) p + … … + 1 ⋅ p = n ( n + 1 ) 2 1 n + 1 = n 2 np + (n-1)p + (n-2)p + …… + 1⋅p =\frac{n(n+1)}{2}\frac{1}{n+1}=\frac{n}{2} np+(n−1)p+(n−2)p+……+1⋅p=2n(n+1)n+11=2n;平均时间复杂度 = O(n)
bool ListDelete(SqList &L,int i,ElemType &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];
}
L.length--;
return true;
时间复杂度分析:
最好情况:新元素插入到表尾,不需要移动元素i = n+1,循环0次;最好时间复杂度 = O(1);
最坏情况:新元素插入到表头,需要将原有的 n 个元素全都向后移动i = 1,循环 n 次;最坏时间复杂度 = O(n);
平均情况:假设新元素插入到任何一个位置的概率相同,即 i = 1,2,3, … , length+1 的概率都是 p = 1 n p=\frac{1}{n} p=n1,循环 n 次;i=2 时,循环 n-1 次;i=3,循环 n-2 次 …… i =n+1时,循环0次。平均循环次数 = n p + ( n − 1 ) p + ( n − 2 ) p + … … + 1 ⋅ p = n ( n − 1 ) 2 1 n = n − 1 2 np + (n-1)p + (n-2)p + …… + 1⋅p =\frac{n(n-1)}{2}\frac{1}{n}=\frac{n-1}{2} np+(n−1)p+(n−2)p+……+1⋅p=2n(n−1)n1=2n−1;平均时间复杂度 = O(n)
ElemType GetElem(SqList L, int i){
return L.data[i-1];
}
int LocateElem(SeqList L,ElemType e){
for(int i=0;i<L.length;i++){
if(L.data[i]==e){
return i+1; //数组下标为i的元素值等于e,返回其位序i+1
}
}
return 0; //退出循环,说明查找失败
}
时间复杂度分析:
最好情况:新元素插入到表尾,不需要移动元素i = n+1,循环0次;最好时间复杂度 = O(1);
最坏情况:新元素插入到表头,需要将原有的 n 个元素全都向后移动i = 1,循环 n 次;最坏时间复杂度 = O(n);
平均情况:假设新元素插入到任何一个位置的概率相同,即 i = 1,2,3, … , length+1 的概率都是 p = 1 n p=\frac{1}{n} p=n1,循环 n 次;i=2 时,循环 n-1 次;i=3,循环 n-2 次 …… i =n+1时,循环0次。平均循环次数 = n p + ( n − 1 ) p + ( n − 2 ) p + … … + 1 ⋅ p = n ( n + 1 ) 2 1 n = n 2 np + (n-1)p + (n-2)p + …… + 1⋅p =\frac{n(n+1)}{2}\frac{1}{n}=\frac{n}{2} np+(n−1)p+(n−2)p+……+1⋅p=2n(n+1)n1=2n;平均时间复杂度 = O(n)