(本文是根据b站小甲鱼的数据结构与算法视频所作笔记,供复习和加强记忆使用)
静态链表
用数组描述的链表叫做静态链表,这种描述方法叫做游标实现法
静态链表存储结构:
#define MAXSIZE 1000
typedef struct
{
ElemType data; //数据
int cur; //游标(Cursor)
} Component,StaticLinkList[MAXSIZE];
这里会发现游标的数字很奇怪,这是因为在静态链表里,数组下标为0的地方是不存储数据的,而最后一个,也就是MAXSIZE-1也是不存储数据的。下表为MAXSIZE-1的”屁股“的游标是指向第一个有数据的元素,因为A的下标是1,所以”屁股“的游标就是1。可以看出,那下标为0的”头“的游标则是第一个没有数据的(除了头和屁股)的格子,也就是下标为5的格子,其他的每一个格子的游标都是它下一个元素的下标。(至于为什么没有B是因为在插入的时候要用)。
(这里的图也出了一点问题,最后一个元素的游标一定是0,不然就结束不了了,后面的图也是有问题的要注意)
初始化静态链表
对静态链表进行初始化相当于初始化数组:
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;
}
这里小甲鱼居然有写,一边看视频一边记的笔者哭了。
静态链表的插入操作
这里看的比较费解,它的意思是,在进行插入操作后,A的游标就会变成新加入的元素B的下标,这样的话根据顺序访问A,A的游标指向了B,所以下一个元素就是B,然后B又把他自己的游标改成了C的下标2,所以就变成了ABCDE的顺序了(总感觉有点掩耳盗铃的感觉)
代码
代码由两部分组成:
1.获得空闲分量的下标:
int Malloc_SLL(StaticLinkList space)
{
int i = space[0].cur;
if(space[0].cur)
{
space[0].cur = space[i].cur;
//把它的下一个分量用来作为备用。
}
return i;
}
2.插入新的数据元素:
在静态链表L中第i个元素之前插入新的数据元素e
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;
}
静态链表的删除操作
代码
/*删除在L中的第i个数据元素*/
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; //k1 = 1;k2 = 5
}
j = L[k].cur; //j = 2
L[k].cur = L[j].cur;
Free_SLL(L,j);
return OK;
}
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;
}
静态链表优缺点总结:
优点:
插入和删除操作时,只需要修改游标而不需要移动元素,从而改进了在顺序存储结构中的插入和删除操作需要移动大量元素的缺点。
缺点:
没有解决连续存储分配(数组)带来的表长难以确定的问题
失去了顺序存储结构随机存取的特性
总的来说静态链表是为了给没有指针的编程语言设计的一种实现单链表功能的方法。