线性表分为顺序存储和链式存储:
顺序存储的就是顺序表,链式存储分为静态链表(借助数组实现),单链表,双链表,循环多链表(这三个都是通过指针实现)
线性表的基本操作:
InitList(&L):初始化表。构建空的线性表。
Length(L):获取表长,返回线性表L的长度。
LocateElem(L,i):按值查找。
GetElem(L,i):按位查找操作,获取表中第i位的元素值。
ListInsert(&L,i,e):插入,在第i个位置插入元素e.
ListDelete(&l,i,&e):删除操作,删除第i位的数据并且通过e返回删除的元素值。
PrintList(L):输出,输出整个线性表中所有的元素。
Empty(L):判断线性表是否为空,是返回true,不是返回false.
DestroyList(&L):销毁操作,销毁线性表,释放线性表L所占的空间。
顺序表基本操作实现:
1.插入操作
bool ListInsert(SqList &L,int i,ElementType e){
if(i<1||i>L.Length+1){ //判断i范围是否有效
return false;
}
if(l.Length>=MaxSize){//判断表空间是否已满
return false;
}
for(int j=L.length;j>=i;j--){//i位置后的所有元素向后移动一个位置
L.data[j] = L.data[j-1];
}
L.data[i-1] = e;//将e放入i位置
L.Length++; //表长度加1
return true;
}
最好情况的时间复杂度为:O(1)
最差情况的时间复杂度为:O(n)
平均的时间复杂度为:O(n)
2.删除操作
bool ListDelete(SqList &L,int i,ElementType &e){
if(i<1||i>L.Length+1){ //判断范围是否有效
return false;
}
e = L.data[i];//删除的值赋给e
for(int j=i;j<L.length;j++){//i之后的所有元素向前移动
L.data[j] = L.data[j-1];
}
L.Length--; //表长度减1
return true;
}
最好情况的时间复杂度为:O(1)
最差情况的时间复杂度为:O(n)
平均的时间复杂度为:O(n)
3,按值查找
int LocateElem(SqList L,ElemType e){
int i;
for(i=0;i<l.Length;i++){
if(L.data[i]==e){
return i+1; //查找成功返回其位序i+1
}
}
return 0;//查找失败返回0
}
最好情况的时间复杂度为:O(1)
最差情况的时间复杂度为:O(n)
平均的时间复杂度为:O(n)
顺序表和链表的比较:
1.存取(读写)方式
顺序表可以顺序存取,也可以随机存取,链表只能从表头开始。
2.逻辑结构和物理结构
顺序表存储时,逻辑上相邻的数据,物理结构上也相邻。而链表逻辑上相邻的数据,物理结构上不一定相邻。
3.查找插入和删除操作
按值查找当顺序表有序时,时间复杂度为O(n),无序时为O(log2n),
按序号查找时,顺序表的时间复杂度为O(1),而链表所有的时间复杂度为O(n).
顺序表删除和插入时平均需要移动半个表的元素,而链表的删除和插入只需要需改指针域就行。因此,链表的存储密度不够大。
4.空间分配
顺序表需要预先分配一块存储空间,预分配过大将会导致空间浪费,过小就会导致溢出。动态分配虽然可以扩充,但是没有足够大的连续存储空间时会导致分配失败,链式存储空间是只在需要的时候就会申请,只要有内存空间就可以分配,操作灵活,高效。