其实所谓静态链表,就是用数组代替指针,来描述单链表。
首先,数组里面的元素是由两个数据域组成,data和cur,其中,data用来存放数据元素,也就是需要处理的数据;cur相当于单链表中的next指针,存放该元素的后继在数组中的下标,cur也叫做游标。这种用数组描述的链表叫做静态链表,这种实现链表的方法也叫游标实现法。
1.静态链表存储结构和初始化
// 静态链表的存储结构
#define MAXSIZE 1000 // 链表的长度
typedef struct
{
ElemType data; // ElemType为数据元素的类型,这里假定为int
int cur; // 游标
}Component, StaticLinkList[MAXSIZE];
在数组中,我们对数组第一个和最后一个元素作为特殊元素处理,不存数据。通常把未被使用的数组元素称为备用链表,而数组的第一个元素(下标为0)的cur就存放备用链表的第一个结点的下标;而数组的最后一个元素的cur则存放第一个有数值的元素的下标,相当于头结点,当链表为空,则为0,0表示空指针。
为了辨明数组中哪些分量未被使用,我们要将所有未被使用过的及已被删除的分量用游标链成一个备用链表。在初始化中,我们将除首尾之外的分量链接成一个备用链表。
// 初始化:将一维数组space中各分量链成一备用链表
void InitList(StaticLinkList space)
{
int i;
for (i = 0; i < MAXSIZE; i++)
space[i].cur = i + 1;
space[MAXSIZE - 1].cur = 0; // 链表为空,最后一个元素的cur为0
}
2.静态链表的插入操作和删除操作
在动态链表结构中,结点的申请和释放分别借用malloc()和free()两个函数来实现。但在静态链表中,操作的是数组,所以我们要手写这两个函数,另外,还有一个求静态链表长度的函数。
// 若备用链表非空,则返回分配的结点下标,否则返回0
int Malloc_SLL(StaticLinkList space)
{
int i = space[0].cur; // 返回第一个备用空闲的下标
if (space[0].cur)
space[0].cur = space[i].cur; // 由于需要拿出一个分量出来使用,所以数组第一个元素的cur得存放原来第一个备用空闲分量的下一个分量
return i;
}
// 将下标k的空闲结点回收到备用链表
void Free_SLL(StaticLinkList space, int k)
{
// 头插法
space[k].cur = space[0].cur;
space[0].cur = k;
}
// 求静态链表的长度
int ListLength(StaticLinkList L)
{
int j = 0;
int i = L[MAXSIZE - 1].cur;
while (i)
{
i = L[i].cur;
j++;
}
return j;
}
// 在L中第i个位置插入新的数据元素e
bool ListInsert(StaticLinkList L, int i, ElemType e)
{
int j, k, l;
k = MAXSIZE - 1;
if (i < 1 || i > ListLength(L) + 1)
return false;
j = Malloc_SLL(L); // j为空闲分量的下标
if (j) // 若j不为0,则表示申请到空闲分量
{
L[j].data = e;
for (l = 1; l < i - 1; l++) // 找到第i-1个元素
k = L[k].cur;
// 插入操作
L[j].cur = L[k].cur;
L[k].cur = j;
return true;
}
return false;
}
// 删除在L中第i个数据元素e
bool ListDelete(StaticLinkList L, int i, ElemType &e)
{
int j, k;
if (i < 1 || i > ListLength(L))
return false;
k = MAXSIZE - 1;
for (j = 1; j <= i - 1; j++) // 找到第i-1个元素
k = L[k].cur;
j = L[k].cur; // j为第i个元素的下标
e = L[j].data; // e保存删除的数据
L[k].cur = L[j].cur
Free_SLL(L, j);
return true;
}
3.静态链表的优缺点
优点:
- 在插入和删除操作时,只需要修改游标,不需要移动元素,从而改进了在顺序存储结构中插入和删除操作需要移动大量元素的缺点
缺点:
- 没有解决连续存储分配带来的表长难以确定的问题
- 失去了顺序存储结构随机存取的特性