对于线性链表,也可用一维数组来进行描述。这种描述方法便于在没有指针类型的高级程序设计语言中使用链表结构。用数组描述的链表,即称为静态链表。
线性表的静态链表存储结构
#define MAXSIZE 1000
typedef struct{
ElemType data;//数据
int cur;//游标(Cursor)
}Component,StaticLinkList[MAXSIZE]
静态链表进行初始化相当于初始化数组
Status InitList(StaticLinkList space){
int I;
for(I = 0;i < MAXSIZE - 1;I++){
space[I].cur = I+1;
space[MAXSIZE-1].cur = 0;
return OK;
}
}
说明
- 对数组的第一个和最后一个元素做特殊处理,他们的data不存放数据
- 我们通常把未使用的数组元素称为备用链表
- 数组的第一个元素,即小标为0的那个元素的cur就存放备用链表的第一个结点的下标
- 数组的最后一个元素,即下标为MAXSIZE-1的cur则存放第一个有数值的元素的下标,相当于单链表中头结点作用
-
最后一个数据的游标指向0 ;!!!图片有误
静态链表中主要解决的是:如何用静态模拟动态链表结构的存储空间分配,也就是需要的时候申请,不需要的时候释放.
在动态链表中,结点申请和释放分别借用C语言的malloc()和free()两个函数来实现
在静态链表中,操作的是数组,不存在像动态链表的结点申请和释放的问题,所以需要自己实现这两个函数,才可以做到插入和删除的操作
静态链表的插入操作
为了辨明数组中哪些分量未被使用,解决的方法是将所有未被使用过的及已被删除的分量用游标链成一个备用的链表
每当进行插入时,便可以从备用链表上取得第一个结点作为待插入的新结点,这里假设在A后边插入B
代码实现
- 首先是获取空闲分量的下标
int Malloc_SLL(StaticLinkList space){
int I space[0].cur;
if(space[0].cur)
space[0].cur = space[I].cur;//把它的下一个分量用来作为备用
return i;
}
Status ListInsert( StaticLinkList L, int I, ElemType e){
int j ,k,l;
k = MAX_SIZE - 1;
if(I <1 || I> ListLength(L) + 1){
return ERROR
}
j = Malloc_SLL(L);
if(j){
L[j].data = e;
for(l = 1; l <= I-1;l++){
k = L[k].cur;
L[j].cur = L[k].cur;
L[k].cur = j;
return OK;
}
return ERROR;
}
}
静态链表的删除操作
Status ListDelete(StaticLinkList L , int i){
int j ,k;
if(I <1 || I> ListLength(L)){
return ERROR
}
k = MAX_SIZE - 1;
for (j = 1;j <= I-1;j++){
k =L[k].cur;
}
j = L[k].cur;
L[k].cur = L[j].cur;
Free_SLL(L,j);
return OK
}
//将小标为k的空闲结点回收到备用链表
void Free_SLL (StaticLinkList space ,int k){
space[k].cur = space[0].cur;
space[0].cur = k;
}
// 返回L中数据元素个数
int ListLength(StaticLinkList L){
int j = 0;
int I = L[MAXSIZE - 1].cur;
while(i){
I = L[I].cur;
j++;
}
return j;
}
静态链表
优点:在插入和删除操作时,只需要修改游标,不需要移动元素,从而改进了在顺序存储结构中的插入和删除操作需要移动大量元素的缺点
缺点:
没有解决连续存储分配(数组)带来的表长难以确定的问题
失去了顺序存储结构随机存取的特征
总的来说,静态链表其实是为了给没有指针的编程语言设计的一种实现单链表共的方法,一般情况我们可以用单链表就不用静态链表了
面试题:如何快速找到未知长度单链表的中间节点
普通方法:首先遍历一遍单链表以确定单链表的长度L.然后再次从头结点出发循环L/2次找到单链表的中间节点 ; 算法复杂度为:O(L+L/2) = O(3L/2)
利用快慢指针原理实现: 设置两个指针 search mid 都是指向单链表的头结点 其中search的移动速度是mid 的2倍. 当*search指向末尾结点时候mid正好就在中间了.这也是标尺的思想
Status GetMIdNode(LinkList L, ElemType *e){
LinkList search,mid;
mid = search =L
while(search->next ! = NULL){
if(search->next->next != NULL){
search = search->next->next;
mid = mid->next;
}else{
search = search->next;
}
}
*e = mid->data;
return OK;
}